目录
前言
在网站设计中,纯粹的HTML格式的网页通常被称为静态网页,其数据都呈现在网页的HTML代码当中,是公开的,因此比较容易获取。在静态网页的抓取任务当中,Requests库能够有效的发送HTTP请求,并获取相应内容。下面先介绍基础内容,然后以获取豆瓣电影TOP250(网页地址为:https://movie.douban.com/top250)的所有电影的名称为例,介绍静态网页的抓取。
一、Requests库安装
pip install requests
二、发送HTTP请求
首先,我们利用Requests库来获取某一个静态页面的内容。利用requests模块的get()方法,并传递参数URL(即需要获取的页面内容的网址),可以得到一个Response对象 r 。
import requests
# 访问CSDN主页
r = requests.get('https://www.csdn.net/')
print("文本编码:", r.encoding)
print("响应状态码:", r.status_code)
print("字符串方式的响应体:", r.text)
通过Response对象,我们可以得到服务器的相应内容。如下所示,加粗为个人常用的:
- r.text:获取服务器相应的内容。
- r.encoding:获取服务器内容使用的文本编码。
- r.status_code:检测响应的状态码。返回200,表示请求成功。返回4xx,表示客户端错误。返回5xx,表示服务器错误响应。
- r.json:Requests 中内置的 JSON 解码器。
- r.content:以字节的方式访问请求响应体。
三、定制Requests
对于有些网页,需要对Requests的参数进行设置才能够获取需要的数据,这包括传递URL参数、定制请求头、发送POST请求、设置超时等等。
1 传递URL参数
有时相位URL的查询字符串传递某种数据,如果是自己构建URL,那么数据一般会根在一个问号的后面,并且以键/值对的形式置于 URL 中。例如, http://httpbin.org/get?key1=val1。
Requests 允许你使用 params 关键字参数,以一个字符串字典来提供这些参数。
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print("URL正确编码:",r.url)
# http://httpbin.org/get?key1=value1&key2=value2
还可以将一个列表作为值传入:
payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.url)
# http://httpbin.org/get?key1=value1&key2=value2&key2=value3
2 定制请求头
请求头Headers提供了关于请求相应或其他发送实体的信息。如果没有指定请求头或者请求的请求头和实际网页不一致,就可能无法返回正确的结果。
对于定制请求头,只需要简单的传递一个 dict 给 headers 参数就可以了。
那么如何找到正确的Headers呢?
首先,用Chrome浏览器打开要求请的网页,右击网页的任意位置,单击“检查”,会弹出下图所示的工作区。
接着,在该工作区中,点击Network选项,这是可能会什么也没有,那么刷新网页,得到如下图所示的页面。
在左侧的资源中找到需要请求的网页并单击,这是在Headers中可以看到Requests Headers的详细信息。
提取请求头的重要部分,可以将代码改为:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36'
}
r = requests.get('https://docs.python-requests.org/zh_CN/latest/user/quickstart.html#id2', headers=headers)
print("响应状态码:", r.status_code)
3 发送POST请求
除了get请求之外,有时需要发送一些编码为表单形式的数据,要实现这个,只需使用post请求,并简单地传递一个字典给 data 参数。
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
# {
# ...
# "form": {
# "key2": "value2",
# "key1": "value1"
# },
# ...
# }
还可以为 data 参数传入一个元组列表。在表单中多个元素使用同一 key 的时候,这种方式尤其有效:
payload = (('key1', 'value1'), ('key1', 'value2'))
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)
# {
# ...
# "form": {
# "key1": [
# "value1",
# "value2"
# ]
# },
# ...
# }
4 超时
可以告诉 requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应。注意,timeout 仅对连接过程有效,与响应体的下载无关。 timeout 并不是整个下载响应的时间限制,而是如果服务器在timeout 秒内没有应答,将会引发一个异常。
requests.get('http://github.com', timeout=0.001)
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request #timed out. (timeout=0.001)
四、 案例:爬取TOP250电影数据
目的:获取豆瓣电影TOP250的所有电影名称,网页地址为豆瓣电影 Top 250
1 网页分析
打开豆瓣电影TOP250的网站,使用“检查”功能查看该网页的请求头,如下图所示
提取重要的请求头:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'Host': 'movie.douban.com'
}
由页面可以看到,第一页只有25个电影,要想获取所有电影名称,需获取10页的内容。现在分析每页内容的网址地址。
单击第二页可以发现网页地址变为:https://movie.douban.com/top250?start=25
单击第三页可以发现网页地址变为:https://movie.douban.com/top250?start=50
因此每多一页,就给网页地址的start参数加上25
2 获取网页
利用requests获取网页的内容:
import requests
def get_movies():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'Host': 'movie.douban.com'
}
for i in range(0, 10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25)
r = requests.get(link, headers=headers, timeout=10)
print(str(i + 1), "页响应状态码:", r.status_code)
print(r.text)
if __name__ == '__main__':
get_movies()
如此,得到的结果只是网页的HTML代码。
3 解析网页
解析网页的内容会在后续介绍。在这,给出解析网页的代码:
import requests
from bs4 import BeautifulSoup
def get_movies():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'Host': 'movie.douban.com'
}
movie_list = []
# div_list = []
for i in range(0, 10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25)
r = requests.get(link, headers=headers, timeout=10)
print(str(i + 1), "页响应状态码:", r.status_code)
# print(r.text)
soup = BeautifulSoup(r.text, "lxml")
div_list = soup.find_all('div')
for each in div_list:
movie = each.a.span.text.strip()
movie_list.append(movie)
return movie_list
if __name__ == '__main__':
get_movies()