Python爬虫基础
Python爬虫
1.Urllib
1.互联网爬虫
- 通过一个程序,根据Url进行爬取网页,获取有用信息
- 使用程序模拟浏览器,去向服务器发送请求,获取响应信息
2.爬虫核心
- 爬取网页:爬取整个网页包含了网页中所有得内容
- 解析数据:将网页中得到的数据进行解析
- 难点:爬虫和反爬虫之间的博弈
3.爬虫用途
- 数据分析/人工数据集
- 社交软件冷启动
- 舆情监控
- 竞争对手监控
pie showData
title 爬虫流量目标行业分析
"出行":20.87
"社交":18.4
"电商":13.38
"O2O":6.28
"政府部门":4.91
"运营商":4.91
"自媒体":3.94
"地图":3.8
"搜索":3.47
"新闻":3.18
"其他":16.88
4.爬虫分类
1.通用爬虫
- 功能
- 访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务
- robots协议
- 一个约定俗成的协议,添加robots.txt文件,来说明本网站哪些内容不可以被抓取,起不到限制作用
- 自己写的爬虫无需遵守
- 缺点
- 抓取的数据大多是无用的
- 不能根据用户的需求来精准获取数据
2.聚焦爬虫
-
功能
- 根据需求,实现爬虫程序,抓取需要的数据
-
设计思路
- 确定要爬取的url
- 如何获取Url
- 模拟浏览器通过http协议访问url,获取服务器返回的html代码
- 如何访问
- 解析html字符串(根据一定规则提取需要的数据)
- 如何解析
- 确定要爬取的url
5.反爬手段
1.User‐Agent
- User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
2.代理IP
-
西刺代理
-
快代理
-
使用透明代理,对方服务器可以知道使用了代理,并且也知道真实IP。
-
使用匿名代理,对方服务器可以知道使用了代理,但不知道真实IP。
-
使用高匿名代理,对方服务器不知道使用了代理,更不知道真实IP。
3.验证码访问
- 打码平台
- 云打码平台
4.动态加载网页
- 网站返回的是js数据,并不是网页的真实数据
- selenium驱动真实的浏览器发送请求
5.数据加密
- 分析js代码
6.urllib库使用
- 模拟浏览器向服务器发送请求
1 | urllib.request.urlopen(url) |
# 获取后直接read()读取的是二进制数据
# 需要再使用decode(“对应编码”)
-
请求到的对象是HttpResponse类型
-
read() 字节形式读取二进制
- rede(5)返回前几个字节
-
readline() 读取一行
-
readlines() 一行一行读取 直至结束
-
getcode() 获取状态码
-
geturl() 获取url
-
getheaders() 获取headers
-
请求网页,请求图片,请求视频
1 | urllib.request.urlretrieve(url,filename) |
7.请求对象的定制
- 定制一个对象,存储url和ua
1 | request = urllib.request.Request(url,data,headers) |
例如:
1 | url1='https://www.baidu.com/' |
- url的组成
- 协议
- http/https
- 主机
- 端口号
- http:80
- https:443
- 路径
- 参数
- 锚点
- 协议
8.编解码
1.get请求方式:urllib.parse.quote()
- 将括号中的内容转为unicode编码的格式
1 | urllib.parse.quote() |
2.get请求方式:urllib.parse.urlencode()
- url的参数存在data中,将data中的内容转为unicode编码的格式
1 | urllib.parse.urlencode(data) |
3.post请求方式
-
post请求的参数必须调用encode(“对应编码”)进行编码
-
参数放在请求对象定制的方法中
# post和get区别
- get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法
- post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法
| GET 请求 | POST 请求 | |
|---|---|---|
| 用途 | 获取数据 | 提交数据(如表单、上传) |
| 参数位置 | 在 URL 中(?id=123) |
在请求体(Body)中 |
| 数据大小 | 受 URL 长度限制 | 理论上无限制 |
| 安全性 | 参数暴露在 URL,不适合传密码 | 参数在 Body 中,相对安全 |
| 幂等性 | 多次请求结果相同(无副作用) | 可能产生副作用(如重复提交订单) |
9.ajax的get请求
1 | # 爬取豆瓣电影前10页数据 |
10.ajax的post请求
-
同理post请求的参数必须调用encode(“对应编码”)进行编码
-
ajax的反爬逻辑
| 普通静态页面 | AJAX 动态加载页面 |
|---|---|
| 一次请求,HTML 里就有全部数据 | HTML 是空的「骨架」,数据由 JS 二次请求填充 |
| requests.get(url)直接拿到数据 | requests.get(url)只拿到空壳 HTML |
| 数据在源码中,正则/XPath 直接提取 | 数据在 JS 执行后的 DOM 中,源码里没有 |
11.URLError\HTTPError
- HTTPError类是URLError类的子类
- 导入的包urllib.error.HTTPError和urllib.error.URLError
- http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。
- 通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让代码更加的健壮,可以通过try‐except进行捕获异常,异常有两类,URLError\HTTPError
12.cookie登录
-
网站通常会有登录页面,不是utf-8
-
在header中添加cookie
13.Handler处理器
- 定制更高级的请求头,随着业务逻辑的复杂,请求对象的定制已经满足不了需求(动态cookie和代理不能使用请求对象的定制)
1 | import urllib.request |
14.代理服务器
- 代理的常用功能
- 突破自身IP访问限制,访问国外站点。
- 访问一些单位或团体内部资源
- 扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
- 提高访问速度
- 扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
- 隐藏真实IP
- 扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。
- 代码配置代理
- 创建Reuqest对象
- 创建ProxyHandler对象
- 用handler对象创建opener对象
- 使用opener.open函数发送请求
1 | import urllib.request |
- 代理池:用列表存储多个ip,每次随机使用
2.解析
1.xpath
- 浏览器安装xpath插件
- 导入xpath
1 | from lxml import etree |
1.解析本地文件
1 | html_tree = etree.parse('XX.html') |
2.服务器响应文件
1 | html_tree = etree.HTML(response.read().decode('utf‐8') |
3.xpath路径
- 获取相应路径的内容
- 得到的是列表
1 | html_tree.xpath(xpath路径) |
# 图片通常会使用懒加载,需要使用懒加载前的路径
4.xpath基本语法
1.路径查询
-
//:查找所有子孙节点,不考虑层级关系
-
/ :找直接子节点
2.谓词查询
-
//div[@id]
-
//div[@id=“maincontent”]
3.属性查询
- //@class
4.模糊查询
-
//div[contains(@id, “he”)]
-
//div[starts‐with(@id, “he”)]
5.内容查询
- //div/h1/text()
6.逻辑运算
-
//div[@id=“head” and @class=“s_down”]
-
//title | //price
2.JsonPath
- 导入JsonPath和json
1 | import json |
1 | obj = json.load(open('json文件', 'r', encoding='utf‐8')) |
# 只能解析本地文件
1 | ret = jsonpath.jsonpath(obj, 'jsonpath语法') |
3.BeautifulSoup
1.基本简介
- BeautifulSoup简称:bs4
- BeautifulSoup,和lxml一样,是一个html的解析器,主要功能也是解析和提取数据
- 效率没有lxml的效率高
- 接口设计人性化,使用方便
2.基础使用
- 导入
1 | from bs4 import BeautifulSoup |
- 创建对象
- 服务器响应的文件生成对象
1 | soup = BeautifulSoup(response.read().decode(), 'lxml') |
- 本地文件生成对象
1 | soup = BeautifulSoup(open('1.html'), 'lxml') |
# 默认打开文件的编码格式gbk所以需要指定打开编码格式
3.节点定位
1.根据标签名查找节点
soup.a 【注】只能找到第一个a
soup.a.attrs
2.函数
-
find(返回一个对象)
- find(‘a’):只找到第一个a标签4.节点信息
- find(‘a’, title=‘名字’)
- find(‘a’, class_=‘名字’)
-
find_all(返回一个列表)
- find_all(‘a’) 查找到所有的a
- find_all([‘a’, ‘span’]) 返回所有的a和span
- find_all(‘a’, limit=2) 只找前两个a
-
select(根据选择器得到节点对象)【推荐】
-
1.element
- eg:p
-
2…class
- eg:.firstname
-
3.#id
- eg:#firstname
-
属性选择器
- [attribute]
- eg:li = soup.select(‘li[class]’)
- [attribute=value]
- eg:li = soup.select(‘li[class=“hengheng1”]’)
- [attribute]
-
层级选择器
-
element element
- div p
-
element>element
- div>p
-
element,element
- div,p
- eg:soup = soup.select(‘a,span’)
- div,p
-
-
4.节点信息
- 获取节点内容:适用于标签中嵌套标签的结构
- obj.string
- obj.get_text()【推荐】
- 节点的属性
- 获取节点属性
- obj.attrs.get(‘title’)【常用】
- obj.get(‘title’)
- obj[‘title’]
3.Selenium
1.Selenium
1.基本简介
- Selenium是一个用于Web应用程序测试的工具。
- Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。
- 支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动真实浏览器完成测试。
- selenium也是支持无界面浏览器操作的。
- 模拟浏览器功能,自动执行网页中的js代码,实现动态加载
2.基础使用
- 下载对应浏览器的操作驱动后导入Selenium
1 | from selenium import webdriver |
- 创建谷歌浏览器操作对象
1 | path = 谷歌浏览器驱动文件路径 |
# 驱动放在解释器文件下不需要加path,其中Chrome可以替换为其他浏览器
- 访问网址
1 | url = 要访问的网址 |
3.元素定位
-
元素定位:自动化要做的就是模拟鼠标和键盘来操作来操作这些元素,点击、输入等等。操作这些元素前首先要找到它们,WebDriver提供很多定位元素的方法
-
方法:
-
find_element(By.ID, ‘’)
1 | eg:button = browser.find_element(By.ID,"su") |
- find_element(By.NAME, ‘’)
1 | eg:name = browser.find_element(By.NAME,'wd') |
- find_element(By.XPATH, ‘’)
1 | eg:xpath1 = browser.find_elements(By.XPATH, '//input[@id="su"]') |
- find_element(By.TAG_NAME, ‘’)
1 | eg:names = browser.find_elements(By.TAG_NAME,'input') |
- find_element(By.CSS_SELECTOR, ‘’)
1 | eg:my_input = browser.find_elements(By.CSS_SELECTOR,'#kw')[0] |
- find_element(By.LINK_TEXT, ‘’)
1 | eg:browser.find_element(By.LINK_TEXT,"新闻") |
4.元素信息
- 获取元素属性
- .get_attribute(‘class’)
- 获取元素文本
- .text
- 获取标签名
- .tag_name
5.交互
- 点击:
- click()
- 输入:
- send_keys()
- 后退操作:
- browser.back()
- 前进操作:
- browser.forword()
- 模拟JS滚动:
- js=‘document.documentElement.scrollTop=100000’
- browser.execute_script(js) 执行js代码
- 获取网页代码:
- page_source
- 退出:
- browser.quit()
2.Phantomjs
-
是一个无界面的浏览器
-
支持页面元素查找,js的执行等
-
由于不进行css和gui渲染,运行效率要比真实的浏览器要快很多
-
基于Selenium,需要导入
-
新版Selenium已弃用
3.Chrome handless
-
Chrome-headless 模式, Google 针对 Chrome 浏览器59版新增加的一种模式,可以在不打开UI界面的情况下使用 Chrome 浏览器,所以运行效果与 Chrome 保持完美一致。
-
需对其进行配置
1 | from selenium import webdriver |
# 可以对其封装
4.requests
1.基本使用
-
与urllib的功能基本一致
-
response的属性以及类型
- 类型 :models.Response
- r.text :获取网站源码
- r.encoding :访问或定制编码方式
- r.url :获取请求的url
- r.content :响应的字节类型
- r.status_code :响应的状态码
- r.headers :响应的头信息
2.get请求
1 | import requests |
- 定制参数
- 参数使用params传递
- 参数无需urlencode编码
- 不需要请求对象的定制
- 请求资源路径中?可加可不加
3.post请求
1 | import requests |
- get和post区别
- get请求的参数名字是params,post请求的参数的名字是data
- 请求资源路径后面可以不加?
- 不需要手动编解码
- 不需要做请求对象的定制
4.代理
- proxy定制
- 在请求中设置proxies参数
- 参数类型是一个字典类型
1 | import requests |
5.cookie定制
-
一般网站需要登录
-
登录时会要求很多参数,并且每次刷新界面都会更新的参数
- 通常是被hidden的
-
需要先获取登录界面的源码
-
再用xpath或bs4解析获取即可
-
还需要图片验证码
-
先获取图片验证码的路径
- 下载图片,再人工识别后在控制台输入验证码
- 这种方法获取验证码图片和访问登录页面时返回的验证码不是同一个
- 需要使用requests的session方法,方法的返回值能使请求变成对象
- 或者使用打码平台
- 下载图片,再人工识别后在控制台输入验证码
5.scrapy
1.scrapy
1.基本介绍
- Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
2.创建scrapy项目
- 在终端输入
1 | scrapy startproject 项目名称 |
-
会生成文件夹
-
再输入
1 | scrapy genspider 爬虫文件名字 网页的域名 |
- 会在spiders文件夹下创建一个爬虫文件
# 不需要加http协议,生成文件时会自动添加
3.项目组成
- spiders
- _init_.py
- 自定义的爬虫文件.py ‐‐‐》生成的爬虫文件,是实现爬虫核心功能的文件
- _init_.py
- items.py ‐‐‐》定义数据结构的地方,是一个继承自scrapy.Item的类
- middlewares.py ‐‐‐》中间件代理
- pipelines.py ‐‐‐》管道文件,里面只有一个类,用于处理下载数据的后续处理。默认是300优先级,值越小优先级越高(1‐1000)
- settings.py ‐‐‐》配置文件,比如:是否遵守robots协议,User‐Agent定义等
4.生成的爬虫文件的基本组成
- 继承scrapy.Spider类
- name = ‘baidu’ ‐‐‐》 运行爬虫文件时使用的名字
- allowed_domains ‐‐‐》 爬虫允许的域名,在爬取的时候,如果不是此域名之下的url,会被过滤掉,多页下载的时候去掉协议和页码范围
- start_urls ‐‐‐》 声明了爬虫的起始地址,可以写多个url,一般是一个
- parse(self, response) ‐‐‐》解析数据的回调函数
- response.text ‐‐‐》响应的是字符串
- response.body ‐‐‐》响应的是二进制文件
- response.xpath()‐》xpath方法的返回值类型是selector列表
- extract() ‐‐‐》提取的是selector对象的是data
- extract_first() ‐‐‐》提取的是selector列表中的第一个数据
5.运行爬虫文件
- 在终端输入
1 | scrapy crawl 爬虫名称 |
# 注意:应在spiders文件夹内执行
6.scrapy架构组成
- 引擎 ‐‐‐》自动运行,无需关注,会自动组织所有的请求对象,分发给下载器
- 下载器 ‐‐‐》从引擎处获取到请求对象后,请求数据
- spiders ‐‐‐》Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是定义爬取的动作及分析某个网页(或者是有些网页)的地方。
- 调度器 ‐‐‐》有自己的调度规则,无需关注
- 管道(Item pipeline) ‐‐‐》最终处理数据的管道,会预留接口供我们处理数据
- 当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。
- 每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
7.scrapy工作原理
- 引擎向spiders要url
- 引擎将要爬取的url给调度器
- 调度器会将url生成请求对象放入到指定的队列中
- 从队列中出队一个请求
- 引擎将请求交给下载器进行处理
- 下载器发送请求获取互联网数据
- 下载器将数据返回给引擎
- 引擎将数据再次给spiders
- spiders通过xpath解析该数据,得到数据或者url
- spiders将数据或者url给到引擎
- 引擎判断,是数据交给管道(Item Pipeline),是url交给调度器处理
flowchart TB
a["引擎"]--url-->b["调度器"]
b--请求-->a
a--解析结果-->c["spiders"]
a--url-->c
c--数据-->a
a--数据-->d["管道"]
a--请求-->e["下载器"]
e--数据-->a
f("互联网")--下载数据-->e
2.scrapy shell
1.基本介绍
- Scrapy终端,是一个交互终端,在未启动spider的情况下尝试及调试爬取代码。 其本意是用来测试提取数据的代码,可以将其作为正常的Python终端,在上面测试任何的Python代码。
- 该终端是用来测试XPath或CSS表达式,查看他们的工作方式及从爬取的网页中提取的数据。 在编写spider时,该终端提供了交互性测试表达式代码的功能,免去了每次修改后运行spider的麻烦。
- 一旦熟悉了Scrapy终端后,其在开发和调试spider时发挥的巨大作用。
2.基础使用
1 | scrapy shell 网址 |
- 语法
- response对象:
- response.body
- response.text
- response.url
- response.status
- response的解析:
- response.xpath() (常用)
- 使用xpath路径查询特定元素,返回一个selector列表对象
- response.css()
- 使用css_selector查询元素,返回一个selector列表对象
- 获取内容 :response.css(‘#su::text’).extract_first()
- 获取属性 :response.css(‘#su::attr(“value”)’).extract_first()
- response.xpath() (常用)
- selector对象(通过xpath方法调用返回的是seletor列表)
- extract()
- 提取selector对象的值
- 如果提取不到值 那么会报错
- 使用xpath请求到的对象是一个selector对象,需要进一步使用extract()方法拆包,转换为unicode字符串
- extract_first()
- 提取seletor列表中的第一个值
- 如果提取不到值会返回一个空值
- 返回第一个解析到的值,如果列表为空,此种方法也不会报错,会返回一个空值
- xpath()
- css()
- 注意:每一个selector对象可以再次的去使用xpath或者css方法
- extract()
3.yield
- 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
- yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
- 简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
4.pymysql的使用步骤
5.CrawlSpider
1.基本介绍
- 继承自scrapy.Spider
- CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发送请求
- 所以,如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用CrawlSpider是非常合适的
2.提取链接
- 链接提取器,在这里就可以写规则提取指定链接
1 | scrapy.linkextractors.LinkExtractor( |
3.模拟使用
- 正则用法:links1 = LinkExtractor(allow=r’list_23_\d+.html’)
- xpath用法:links2 = LinkExtractor(restrict_xpaths=r’//div[@class=“x”]')
- css用法:links3 = LinkExtractor(restrict_css=‘.x’)
4.提取连接
- link.extract_links(response)
5.注意事项
# callback只能写函数名字符串, callback=‘parse_item’
# 在基本的spider中,如果重新发送请求,那里的callback写的是 callback=self.parse_item
# follow=true 是否跟进 就是按照提取连接规则进行提取
6.运行原理
flowchart LR
a["起始url"]--response-->b
b["parse"]---->c[url4]
b---->d[url1]
b---->e[url2]
b---->f[url3]
c---->g[parse_item]
e---->g
f---->g
d---->g
6. 数据入库
1.settings配置参数
1 | DB_HOST = '192.168.231.128' |
2.管道配置
1 | from scrapy.utils.project import get_project_settings |
7.日志信息和日志等级
1.日志级别
- CRITICAL:严重错误
- ERROR: 一般错误
- WARNING: 警告
- INFO: 一般信息
- DEBUG: 调试信息
# 默认的日志等级是DEBUG
# 只要出现了DEBUG或者DEBUG以上等级的日志
# 那么这些日志将会打印
2.settings.py文件设置
- 默认的级别为DEBUG,会显示上面所有的信息
- 在配置文件中 settings.py
- LOG_FILE : 将屏幕显示的信息全部记录到文件中,屏幕不再显示,注意文件后缀一定是.log
- LOG_LEVEL : 设置日志显示的等级,就是显示哪些,不显示哪些
8.scrapy的post请求
1.重写start_requests方法
1 | def start_requests(self) |
2.start_requests的返回值
1 | scrapy.FormRequest(url=url, headers=headers, callback=self.parse_item,formdata=data) |
- url: 要发送的post地址
- headers:可以定制头信息
- callback: 回调函数
- formdata: post所携带的数据,这是一个字典
9.代理
- 到settings.py中,打开一个选项
1 | DOWNLOADER_MIDDLEWARES = { |
- 到middlewares.py中写代码
1 | def process_request(self, request, spider): |