python爬虫-2-requests库

学习爬虫,最基础的便是模拟浏览器向服务器发出请求

实例引入

模拟发送一个请求,把网页的源代码获取下来。

可以利用requests库中的get方法来获取网页中的信息,为进一步提取所需信息做准备。
例如:

1
2
3
4
5
6
7
8
9
# coding=utf-8
import requests
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
url = 'https://oi-wiki.org/'
r = requests.get(url)
print(r)
print(r.text)

该代码会将https://oi-wiki.org/网页内容爬取并输出。

基本知识

GET请求

1
2
3
4
5
6
7
# coding=utf-8
import requests

url = 'http://httpbin.org/get'
r = requests.get(url)
print(r)
print(r.text)

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<Response [200]>
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-600e6a30-263a11523bc6ff097314f31d"
},
"origin": "140.250.245.147",
"url": "http://httpbin.org/get"
}

当然,我们也还可以在GET请求时增加一些参数,如下:
http://httpbin.org/get?name=rain&university=XDU

get方法中,我们可以指定params参数来达到传递参数的效果。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
# coding=utf-8
import requests

params = {
'name': 'rain',
'university': 'XDU'
}

url = 'http://httpbin.org/get'
r = requests.get(url, params=params)
print(r)
print(r.text)

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<Response [200]>
{
"args": {
"name": "rain",
"university": "XDU"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-600e6b0c-13dea24830332ab92ef3cc91"
},
"origin": "140.250.245.147",
"url": "http://httpbin.org/get?name=rain&university=XDU"
}

观察发现,返回内容为json格式,我们可以直接利用json()方法将该文本转化为字典。如下:

1
2
3
4
url = 'http://httpbin.org/get'
r = requests.get(url, params=params)
dict = r.json()
print(dict)

但是当返回格式不是json时,会抛出异常。

提取信息

我们可以利用正则表达式获取所虚信息,如:

1
2
3
4
5
6
7
8
9
10
import requests
import re

url = 'http://static1.scrape.cuiqingcai.com/'
r = requests.get(url, verify=False)
print(r)
pattern = re.compile('<h2.*?>(.*?)</h2>', re.S)
tittle = re.findall(pattern, r.text)

print(tittle)

结果为:

1
['霸王别姬 - Farewell My Concubine', '这个杀手不太冷 - Léon', '肖申克的救赎 - The Shawshank Redemption', '泰坦尼克号 - Titanic', '罗马假日 - Roman Holiday', '唐伯虎点秋香 - Flirting Scholar', '乱世佳人 - Gone with the Wind', '喜剧之王 - The King of Comedy', '楚门的世界 - The Truman Show', '狮子王 - The Lion King']

代码参数的verify则是省去网站认证。

抓取二进制数据

图片、音频、视频这些文件本质上都是由二进制码组成,想要抓取它们,就要拿到它们的二进制数据。
例如我们想要抓取github的图标,网址为:https://github.com/favicon.ico
代码如下:

1
2
3
4
5
6
import requests

url = 'https://github.com/favicon.ico'
r = requests.get(url)
print(r.text)
print(r.content)

结果如下:

1
2
:�������O    
b'\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00 \x00(\x05\x00\x00&\x00\x00\x00

前者出现乱码,后者结果带有一个b,这代表是byte类型的数据。

通过以下代码保存图片:

1
2
3
4
5
6
import requests

url = 'https://github.com/favicon.ico'
r = requests.get(url)
with open('favicon.ico', 'wb') as f:
f.write(r.content)

设置headers

某些网站会检查请求的headers信息,在不设置headers时,某些网站可能拒绝访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

headers = {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/87.0.4280.141 Safari/537.36'
}

url = 'https://movie.douban.com/top250'
r = requests.get(url, headers=headers)
print(r)
print(r.text)

当不设置headers时,豆瓣会拒绝访问。

POST请求

利用requests.post()方法即可。

高级用法

文件上传

1
2
3
4
5
import requests

files = {'file': open('favicon.ico', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
print(r.text)

Cookies

1
2
3
4
5
6
7
import requests

url = 'http://www.baidu.com'
r = requests.get(url)
print(r.cookies)
for key, value in r.cookies.items():
print(key + ": " + value)

结果如下:

1
2
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ: 27315

利用Cookies可以模拟登录:

1
2
3
4
5
6
7
8
9
import requests
headers = {
'Cookie': 'Github中的Cookies',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/87.0.4280.141 Safari/537.36'
}
url = 'https://github.com/'
r = requests.get(url, headers=headers)
print(r.text)

结果如下:

1
2
3
...
<meta name="user-login" content="XdBirdie">
...

发现存在含有用户特征的信息,说明我们模拟了登录的状态。

Cookie还可以通过下面的方法设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

cookies = 'Github中的Cookies'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/87.0.4280.141 Safari/537.36'
}
jar = requests.cookies.RequestsCookieJar()
for cookie in cookies.split(';'):
key, value = cookie.split('=')
print(key, value)
jar.set(key, value)
url = 'https://github.com/'
r = requests.get(url, cookies=jar, headers=headers)
print(r.text)

可以达到同样的效果。

Session维持

考虑如下代码:

1
2
3
4
5
6
import requests

url = 'http://httpbin.org/cookies'
r = requests.get(url + '/set/number/12345678')
r = requests.get(url)
print(r.text)

输出结果为:

1
2
3
{
"cookies": {}
}

但是利用Session

1
2
3
4
5
url = 'http://httpbin.org/cookies'
s = requests.Session()
s.get(url + '/set/number/12345678')
r = s.get(url)
print(r.text)

输出结果为:

1
2
3
4
5
{
"cookies": {
"number": "12345678"
}
}e4

SSL证书验证

现在很多网站都要求使用HTTPS协议,但是有些网站可能并没有设置好HTTPS证书,或者网站的HTTPS证书不被认可。这时,这些网站可能就会出现SSL证书错误的提示。

可以使用verify参数控制是否验证证书,如果将其设置为False,在请求时就不会再验证证书是否有效。否则默认值为True,会自动验证。

超时设置

当客户端或者服务器网络响应延迟较高甚至无响应时,为防止服务器不能及时响应,应该设置一个超市时间,当超出此事件还未响应时,报错。

设置timeout参数即可。

例如:

1
2
3
4
import requests
url = 'http://httpbin.org/get'
r = requests.get(url, timeout=1)
print(r.text)

然而链接分为两个阶段,链接阶段(connect)和传送阶段(read time),前面设置的timeout设置的时间是两段时间之和,也可以选择分别设置时间限。如下:

1
2
3
4
import requests
url = 'http://httpbin.org/get'
r = requests.get(url, timeout=(0.4, 0.6))
print(r.text)

如果想永久等待,可以直接将timeout设置为None,或者不设置,因为默认值为None

身份认证

可以使用requests自带的身份认证功能,通过auth参数即可设置。

例如:

1
2
3
4
5
6
7
import requests
from requests.auth import HTTPBasicAuth

url = 'https://static3.scrape.cuiqingcai.com/'
r = requests.get(url, auth=HTTPBasicAuth('admin', 'admin'), verify=False)
print(r.status_code)
print(r.text)

但是相对繁琐,所以python提供了另一种方式进行身份认证:

1
2
3
4
5
6
import requests

url = 'https://static3.scrape.cuiqingcai.com/'
r = requests.get(url, auth=('admin', 'admin'), verify=False)
print(r.status_code)
print(r.text)

requests还提供了其他认证方式,如OAuth认证,不过需要安装oauth包。

1
pip3 install requests_oauthlib

代理设置

对于大规模并且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面,更有甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。
为了防止这种情况发生,需要设置代理来解决问题,这是就需要用到proxies参数。