对于请求、响应、http等知识还处于迷迷惑惑的状态,理论知识以后要慢慢啃
这次要学的爬虫框架:requests,
1.requests
这里先说一下requests和urllib的区别
1)构建参数:在构建请求参数时,第一种需要将请求参数使用urllib库的urlencode方法进行编码预处理,非常麻烦
2)请求方法:发送get请求时,第一种使用的urllib库的urlopen方法打开一个url地址,而第二种直接使用requests库的get方法,与http请求方式是对应的,更加直接、易懂
3)请求数据:第一种按照url格式去拼接一个url字符串,显然非常麻烦,第二种按顺序将get请求的url和参数写好就可以了
4)处理响应:第一种处理消息头部、响应状态码和响应正文时分别使用.info()、.getcode()、.read()方法,第二种使用.headers、.status_code、.text方法,方法名称与功能本身相对应,更方便理解、学习和使用
5)连接方式:看一下返回数据的头信息的“connection”,使用urllib库时,”connection”:”close”,说明每次请求结束关掉socket通道,而使用requests库使用了urllib3,多次请求重复使用一个socket,”connection”:”keep-alive”,说明多次请求使用一个连接,消耗更少的资源
6)编码方式:requests库的编码方式Accept-Encoding更全,在此不做举例
1.1 get和post请求
- 使用requests发送get请求将百度搜索的页面源码爬回来
1 | import requests |
- 发送post请求,也就是直接调用post方法
1 | r = requests.post(http://httpbin.org/post,data={'key':'data'}) |
1.2通过URL传递参数
URL不仅仅是一个网址,我们再访问url的时候经常会带上一些查询的字符串,即请求参数
也就是在使用get请求的时候所说的将信息放在车顶上。requests允许通过字典或字符串来传参
1 | payload = {'key1':'value1','key2':'value2'} |
1.3设置超时
请求时设置等待时间,以免等待太久,在请求时给参数timeout一个数字,单位是秒。超出时间未返回结果即报错
1 | r=requests.get("https://github.com",timeout=0.01) |
1.4设置请求头
请求不到数据,而又没加请求头,在确认请求正确的前提下,多半是爬虫的身份被识破了。
可以通过添加请求头,来伪装浏览器发送请求
1 | url = "https://movie.douban.com/top250" |
对比urllib的使用,语句确实要简单很多
1.5 post请求
1 | payload = {'key1':'value1','key2':'value2'} |
请求成功并返回结果,form字段中字典和刚才传入的字典{‘key1’:’value1’,’key2’:’value2’}
1.6 返回状态码
1 | r = requests.get('http://httpbin.org/get') |
1.7 设置代理IP
访问网络用的协议是TCP/IP,也就是访问网络必须要有一个IP地址,每个人的Ip地址是唯一的。
代理IP是指本机先访问代理服务器,然后代理服务器通过代理IP去访问指定网页。这样网页留下的记录就是代理IP。
一般的服务器在发现某个IP访问频率过高的时候会采取封禁操作,所以代理IP就成了防止爬虫被BAN的利器。
1 | proxies = {'http':'http://10.10.1.10:3128'} |
免费的ip代理大多无法正常使用,想要使用代理可能还是要vip
1.8 模拟登陆校园网
1 | # -*- coding: utf-8 -*- |
2.BeautifulSoup
对源码进行解析和数据提取
2.1 定义
将html文档转换成树形结构,每个节点都是python对象。可以将节点对象归纳为四种:
Tag
NavigableString
- BeautifulSoup
- Comment
2.2 语法
1 | from bs4 import BeautifulSoup |
- print(bs):文档整体就是BeautifulSoup
- print(bs.tittle):Tag及其内容,获取找到的第一个内容
- print(bs.tittle.string):NavigableString,标签里的内容(字符串)
- print (bs.a.attrs):获取标签中的全部属性,以键值对保存在字典
- print(bs.a.string):Comment是一个特殊的NavigableString,输出内容不包含注释
2.3遍历文档树
.contents:获取tag的所有子节点,返回一个list
print(bs.head.contents);获取某一子节点print(bs.head.content[i])
.children:获取tag的所有子节点,返回一个生成器
for child in bs.head.children:
print(child)
.descendants:获取tag的所有子孙节点,返回一个生成器
- .strings:获取tag的所有子孙节点中的内容
- stripped_strings:与strings用法一致,可以消去空白
- .parent:获取tag的所有父节点
- .parents:递归得到父辈元素的所有节点,返回生成器
- .previous_sibling:获取当前tag的上一个节点
- .next_sibling:获取当前tag的下一个节点
- .previous_siblings:获取当前tag的上面所有兄弟节点,返回生成器
- .next_siblings:获取当前tag的上面所有兄弟节点,返回生成器
- .previous_element:解析过程中上一个解析对象
- .next_element:解析过程中下一个解析对象
- .previous_elements:向前访问文档的解析内容,返回生成器
- .next_elements:向后访问文档的解析内容,返回生成器
- .has_attr:判断tag是否包含属性
2.4 元素定位
2.4.1find_all()
- 字符串过滤,查找所有与字符串匹配的文档,返回列表
t_list = bs.find_all(“a”)
结果:a标签及其内容都能找到
- 正则表达式搜索,使用search方法来匹配内容
t_list = bs.find_all(re.compile(“a”))
结果:含有a的标签及其内容都能找到
- kwargs 参数:通过属性进行定位
t_list = bs.find_all(id = “head”)
含有id=head这一属性的标签及其子内容
t_list = bs.find_all(class_=True)
有class属性的标签及其子内容
- text参数:通过文本中想要的内容定位
t_list = bs.find_all(text =“hao123”)
返回hao123字符串文本
t_list = bs.find_all(text = re.compile(“/d”))
利用正则表达式查找包含特定文本的内容
- limit参数:限制想要的数量
t_list = bs.find_all(“a”,limit=3)
找出所有a,从前往后只找3个
2.4.2select()
以标签来查找
t_list = bs.select(“a”)
==t_list = bs.find_all(“a”)
以类名(manv)来查找
t_list = bs.select(“.manv”)
以id(u1)来查找
t_list = bs.select(“#u1”)
以属性来查找
t_list = bs.select(“a[class=’manv’]”)
通过父子标签查找
t_list = bs.select(“head>tittle”)
通过类名(mnav)找到类名为(bri)的兄弟标签
t_list = bs.select(“.mnav~.bri”)
获得文本内容
t_llist.get_text()
3.selenium
3.1基础用法
- 创建浏览器对象
1 | from selenium import webdriver |
请求页面
1 | driver.get("https://www.baidu.com/") |
!!!无头请求模式:以Firefox为例,谷歌就把Firefox改成Chrome
1 |
|
页面的基本操作(点击、输入)
1 |
|
保存网页截图
1 |
|
获取渲染之后的数据
1 |
|
据说上面方法获取的页面源码不标准,下面介绍另一种方法:
1 |
|
请求页面后的cookie值
1 |
|
查看当前页面路径
1 |
|
关闭页面和浏览器
1 |
```
关闭页面
driver.close()
关闭浏览器
driver.quie()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
## 3.2 元素定位的方法
1. 通过标签的id定位
`ret1 = driver.find_element_by_id("anony-nav")`
以对象形式保存
2. 通过标签的id值获取多个标签
`ret2 = driver.find_elements_by_id("anony-nav")`
以列表形式保存,元素为对象
3. 通过标签的class属性值获取标签
`ret3 = driver.find_elements_by_class_name(" ")`
同样是列表形式,这个属性有多少标签就对应多少个对象
4. 通过xpath获取a标签
`ret4 = driver.find_elements_by_xpath("")`
括号中的内容通过在浏览器中右击a标签–copy–coyp xpath,获取其在标签树上的路径
5. 通过标签包裹的文本“下载豆瓣App”获取元素列表
`ret5 = driver.find_element_by_link_text("下载豆瓣App")`
6. 通过包含的文本内容模糊定位
`ret6 = driver.find_elements_by_partial_link_text(“豆瓣)`
7. 通过标签名获取元素列表
`ret7 = driver.find_elements_by_tag_name("div")`
8. 获取`<h1>`标签包裹的文本内容及属性1
2
1.1.先找到元素对象
ret8 = driver.find_element_by_tag_name(“h1”)
2.获取元素内容
ret8.text
3.获取href属性值
ret8.get_attribute(“href”)
1
2
3
4
5
6
## 3.3 selenium的其他方法
### switch页面
1. 切换浏览器窗口1.获取当前所有窗口
current_windows = driver.window_handles
以列表的形式保存2.根据窗口索引进行切换
driver.switch_to.window(current_windows[1])
1
2
控制页面的前进和后退driver.forward()
driver.back()1
2
3
4
5
6
7
8
switch_to进入嵌套网页
iframe是html中常用的一种技术,即一个页面中嵌套了另一个网页,selenium默认访问不了iframe中的内容,比如登录窗口(通过控制台可以看到登录窗口实际是另一个网站),对应的解决思路是:
`driver.switch_to.frame(0)`括号内是索引值,从0开始
### 进行自动化登录
先点击密码登录
driver.find_element_by_xpath(“”).click()
获取输入框标签
driver.find_element_by_xpath(“input的路径”).send_keys(“账号/密码”)
最后点击登录
driver.find_element_by_xpath(“”).click(q)1
2
触发某个事件之后,页面出现弹框提示,处理这个提示或者获取提示信息方法如下:
alert = driver.switch_to_alert()
接收警告框内容
text = driver.switch_to_alert().text
print(text)
处理警告框
1.点击确认
driver.switch_to.alert.accept()
2.点击取消
driver.switch_to.alert.dismiss()
3.如果alert弹框上有文本框,可以输入文字
driver.switch_to.alert.sendkeys()
```