python爬虫篇2—请求和解析库概述
? 前言: 为了节省时间和避免赘述,很多内容我都会省略,因为这些内容看官方文档或者别人写的详细博客即可,我这里仅仅做概述,方便后面写案例。
? 本文思维导图:
一、request库:
1. 功能概述:
? request库是一个python第三方爬虫库,也是我们最为常用的请求库之一。
? 针对于静态网页,request库是最佳选择,其不仅可以实现get请求,也可以实现post请求等操作。
2. 安装方法:
? 安装方法一:
1. 打开windows的命令行窗口(win+r 输入 cmd即可打开)
2. 输入: pip install request 即可安装
? 安装方法二:
1. 对于集成环境的朋友来说,直接使用自带的安装库的方法即可
? 可以使用下面的代码检验是否安装成功:
import requests
url = 'https://www.baidu.com'
response = requests.get(url)
print(response.content.decode('utf-8'))
? 如果安装成功,结果如下:
3. 简单案例:
? 案例是最好的解释。
import requests
url = 'https://www.baidu.com'
response = requests.get(url)
print(response.status_code)
? 结果为:
200
? 那么,上面的代码中涉及到了两个知识点:
含义: get请求方式
参数1: url,需要请求的链接地址
含义: 响应对象
属性1:status_code ,响应状态码,200表示正常
4. response对象详解:
? response对象有几个重要的属性要说一说。
? 这个属性还是有用的,因为有时候网页会有重定向,即我们访问的是A网址,但是重定向后实际访问的是B网址,通过这个属性我们可以确定究竟访问的是哪个网页。
- status_code属性: 返回响应状态码
- cookies属性: 返回cookie对象
- text属性: 返回网页的源码,但是是按照chardet模块推测出的编码进行解码的结果。
- content属性:返回源码的bytes形式结果
5. get请求:
? get请求是平时我们最常用的请求方式之一。在requests模块中,提供给我们了非常方便的get请求方式:
import requests
url = 'http://www.baidu.com'
response = requests.get(url)
print(response.status_code)
常用的参数:
参数 | 作用 |
---|
url | 请求的地址 | headers | 请求头参数(字典) | params | 请求的参数(字典) | cookies | 请求的cookies参数(字典) | timeout | 超时时间设置 |
简单案例:
? 之前我们请求百度,可以发现百度返回的内容非常少,这是我们被百度检测出我们是一个爬虫,因此返回给我们的内容十分的少。
? 这里,我们使用带有headers参数的get请求去请求百度网页,这里为了直观的看到结果,我们把返回的源码保存到一个html文件中:
import requests
url = 'http://www.baidu.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
}
response = requests.get(url,headers=headers)
result = response.content.decode('utf-8')
f = open('test.html','w',encoding='utf-8')
f.write(result)
f.close()
? 结果如下:
百度搜索案例:
? 这里,我们使用百度搜索案例来演示一下params这个参数的用法。
? 首先,基于前端的简单知识(在上一篇中提及过),我们可以知道url http://xxxx/?id=1 中的问号后面接的是参数,因此,我们观察一下百度搜索的url:
https://www.baidu.com/s?wd=python
? 可以知道,它实际上是通过参数wd来判断你搜索的内容的,因此,我们可以这么来写我们的代码:
import requests
url = 'https://www.baidu.com/s?'
target = input('请输入你想要搜索的内容:')
params = {
'wd' : target,
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
'Cookie': 'BIDUPSID=4CB26999F28A00A64AA6BE786D45B9A9; PSTM=1623650616; __yjs_duid=1_a457dc40612f68c8a71b918beebc7b7d1623650934507; BD_UPN=12314753; BDUSS=ViVDExTE5SMlZ6aUd6UlZndWdLREtESDUzMUhzRVNEeWQ3WHVoTHZKa2JUMVJoRUFBQUFBJCQAAAAAAAAAAAEAAABpREyizsSz8zY2NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvCLGEbwixhc1; BDUSS_BFESS=ViVDExTE5SMlZ6aUd6UlZndWdLREtESDUzMUhzRVNEeWQ3WHVoTHZKa2JUMVJoRUFBQUFBJCQAAAAAAAAAAAEAAABpREyizsSz8zY2NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvCLGEbwixhc1; BAIDUID=9FA5CAAD04AA64664A5A35D065D065F9:FG=1; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; ab_sr=1.0.1_N2NjZjI2OWNkZGQ5ZjcyMTIxYzEwNjQwODA5NDI3OGZlNThkYzMxOTYyZjIwOThiZDI3YjQ2ZTYzNzM2MDE5MjMwM2IyNzU0NTE0ZGRhMzQ2OGQwZmRmN2Q5MzhjOWYyODE4NGQzOTJkMWQxMDc0OTIyODM2ZmE3YjgzNzg3YmM5OGM3NGU0NDMxNzQ3Mzk4ZTY4ZGI0M2IzYmY2ZjI5OWUxMjM4ZGRmM2MyMDlkMDdhYzRjYjU4M2M3YjAwOTkw; H_PS_PSSID=26350; H_PS_645EC=5222lq27BgNSzJVJHM%2BGLOhAPQYORidu8wdU1IM8odpIQ5jkd3wiey6dLivbK05hfv1sJaQzcjgc; BAIDUID_BFESS=9FA5CAAD04AA64664A5A35D065D065F9:FG=1; baikeVisitId=fce62568-7213-40b8-b559-bf44b3e19c3f; BDSVRTM=0'
}
response = requests.get(url=url,headers=headers,params=params)
result = response.content.decode('utf-8')
f = open('test.html','w',encoding='utf-8')
f.write(result)
f.close()
? 结果如下:
? 这里我要提及一句,我记得一年前我写这个爬虫的时候,请求头只需要带上user-agent即可,但是现在必须还带上cookie,不然会被百度识别出来是爬虫。
6. post请求:
? post请求也是我们网站中最常用的请求方式之一,一般提交表单几乎都是post请求。而,在requests模块中,post请求与get请求的使用方法上差别在于参数(params与data):
data: 接收一个字典,里面爬虫发出的数据
? 下面举一个例子,比如豆瓣登录页面,我们知道想要登录肯定是需要输入用户名和密码的,那么我们输入的用户名和密码就是参数data中的value,那么key是哪个呢?这里有两个方法,一个就是抓包才看;另外一个就是看其css代码,如下:
? 不难看出,key值分别为username and password 。
? 因此,我们传入的data参数为:
data = {
'username':'xx',
'password':'123456'
}
7. 代理设置:
? 使用代理,有两个目的:
1. 提高访问效率
2. 减少自己ip暴漏风险
? 因为,一个人正常人不可能在1s内访问网页几十次,但是几十个人可以在1s内访问几十次。代理ip就是这个道理,你可以构建一个ip池,这样你的爬虫可以使用不同的ip,达到1s内访问几十次的目的。
? 而,在requests库中,get、post请求方法中都有一个参数 proxies ,这个参数就是设置代理使用的。
? 使用方法如下:
import requests
proxies = {
'http/https':'http/https:ip:port',
'http/https':'http/https:ip:port',
'http/https':'http/https:ip:port',
'http/https':'http/https:ip:port'
}
requests.get(url,proxies=proxies)
8. 会话维持:
? 登录网站需要post请求,但是post请求是一次性的,相当于你登录成功后就又断开了,因此想要保持连接,我们称为会话维持,还是很形象。
? 使用思路如下:
import requests
session = requests.session()
session.post(.....)
response = session.get(....)
二、lxml库:
? 解析库有很多,经典的比如:lxml、re、bs4、pyquery等。掌握1-2个即可,其它的了解一下就可以了,反正又用不到那么多是吧。
1. 安装方法:
? 安装方法类似request安装方法,这里不赘述。
2. 使用案例:
from lxml import etree
text = '''
<body>
<div class="key">
<div class="iocnBox"><i class="iconfont icon-delete"></i></div>
<div class="empty">清空</div>
<textarea placeholder="在此述说新年寄语..." rows="1" class="van-field__control"></textarea>
<div class="buts">发送</div>
</div>
'''
html = etree.HTML(text)
? 通过上面的代码中,不难看出,想要使用lxml的一个前提是你已经获得了网页源代码。
? 另外,使用lxml的第一个步骤就是初始化,生成一个lxml对象,这里我们用变量html接收。
3. 寻找节点/标签:
语法 | 含义 |
---|
nodename(节点名字) | 直接根据写的节点名字查找节点,如:div | // | 在当前节点下的子孙节点中寻找,如://div | / | 在当前节点下的子节点中寻找,如:/div | . | 代表当前节点(可省略不写,就像我们有时候写的相对路径),如:./div | … | 当前节点的父节点,如:…/div |
? 感觉上面的说明还是很详细了,但是还是需要一些例子来告诉你如何使用它们。
? 首先,我们的网页源代码为:
text = '''
<body>
<div>这时测试的div</div>
<div>
<div>
这是嵌套的div标签
<p>
这时嵌套的p标签
</p>
</div>
</div>
<p>这时测试的p</p>
</body>
'''
? 那么,问题一:找到所有的div标签?
html = etree.HTML(text)
result = html.xpath('//div')
? 问题二:找到div里面的p标签?
html = etree.HTML(text)
result = html.xpath('//div//p')
? 问题三:找到最后一个p标签?
html = etree.HTML(text)
result = html.xpath('//body/p')
? 打印一下第一个问题的结果:
[<Element div at 0x17e41ae8ec8>, <Element div at 0x17e41ae8f08>, <Element div at 0x17e41ae8448>]
? 可以看见,返回的是一个列表,里面有三个元素,对应了三个div标签。
4. 筛选节点:
? 当我们使用筛选时,筛选的方法都是包含在[](中括号)中的。
属性筛选
方法名\符号 | 作用 |
---|
@ | 获取属性或者筛选属性,如:@class | contains | 判断属性中是否含有某个值(用于多值判断),如:contains(@class,‘hello’) |
? 一个小例子:
from lxml import etree
text = '''
<div class="hello">
<p>Hello,this is used to tested</p>
</div>
<div class="hello test hi">
<div>
<div>你好,这是用于测试的html代码</div>
</div>
</div>
<div class="button">
<div class="menu">
<input name="btn" type="button" value="按钮" />
<div>
</div>
'''
html = etree.HTML(text)
hello_tag = html.xpath('//div[@class="hello"]')
print(hello_tag)
input_tag = html.xpath('//input[@name="btn"]')
print(input_tag)
hello_tags = html.xpath('//div[contains(@class,"hello")]')
print(hello_tags)
按序选择
? 有时候我们会有这样的需求,我们爬取的内容是一个table标签(表格标签),或者一个ul(标签),了解过html的应该都知道这样的标签,内部还有很多标签,比如table标签里就有tr、td等,ul里面就有li标签等。对于这样的标签,我们有时候需要选择第一个或者最后一个或者前几个等。这样的方式我们也可以实现。
方法 | 作用 |
---|
last() | 获取最后一个标签 | 1 | 获取第一个标签 | position() < = > num | 筛选多个标签(具体见实例) |
? 注意:这里需要注意这里的序是从1开始而不是从0开始。
? 一个小例子:
from lxml import etree
text = '''
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
'''
html = etree.HTML(text)
first_tag = html.xpath('//li[1]')
print(first_tag)
last_tag = html.xpath('//li[last()]')
print(last_tag)
li_tags = html.xpath('//li[position() < 6]')
print(li_tags)
逻辑和计算
? 其实在写筛选时是可以加入逻辑方法的,如:and、or、>、>=等。当然也是可以写入一些计算方法的,如:+、-等。
? 下面给出示例:
from lxml import etree
text = '''
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
'''
html = etree.HTML(text)
second_tag = html.xpath('//li[position() = 2]')
print(second_tag)
tags = html.xpath('//li[position() = 1 or position() = 2]')
print(tags)
three_tags = html.xpath('//li[position()<4]')
print(three_tags)
5. 获取内容:
? 我们寻找标签、筛选标签的最终目的就是获取它的属性或者文本内容。下面讲解获取文本和属性的方法。
方法 | 作用 |
---|
@ | 获取属性或者筛选属性 | text() | 获取文本 |
? 获取文本举个例子:
from lxml import etree
text = '''
<div class="hello">
<p>Hello,this is used to tested</p>
</div>
<div class="hello test hi">
<div>
<div>你好,这是用于测试的html代码</div>
</div>
</div>
<div class="button">
<div class="menu">
<input name="btn" type="button" value="按钮" />
<div>
</div>
'''
html = etree.HTML(text)
content = html.xpath('//div/p/text()')
print(content)
content_two = html.xpath('//div[position() = 2]/text()')
print(content_two)
content_three = html.xpath('//div[position() = 2]//text()')
print(content_three)
? 获取属性也举个例子:
from lxml import etree
text = '''
<div class="hello" name="test">
<p>Hello,this is used to tested</p>
</div>
<div class="hello test hi">
<div>
<div>你好,这是用于测试的html代码</div>
</div>
</div>
<div class="button">
<div class="menu">
<input name="btn" type="button" value="按钮" />
<div>
</div>
'''
html = etree.HTML(text)
first_div_class = html.xpath('//div[@class="hello"]/@name')
print(first_div_class)
input_tag_class = html.xpath('//input/@name')
print(input_tag_class)
|