友情提示:代码全部基于 Python3.6 实现
第一节我们简单介绍了爬虫的基本原理,理解原理可以帮助我们更好的实现代码。Python 提供了非常多工具去实现 HTTP 请求,但第三方开源库提供的功能更丰富,你无需从 socket 通信开始写,比如使用Pyton内建模块 urllib
请求一个 URL 代码示例如下:
import ssl
from urllib.request import Request
from urllib.request import urlopen
context = ssl._create_unverified_context()
# HTTP 请求
request = Request(url="https://foofish.net/pip.html",
method="GET",
headers={"Host": "foofish.net"},
data=None)
# HTTP 响应
response = urlopen(request, context=context)
headers = response.info() # 响应头
content = response.read() # 响应体
code = response.getcode() # 状态码
发起请求前首先要构建请求对象 Request,指定 url 地址、请求方法、请求头,这里的请求体 data 为空,因为你不需要提交数据给服务器,所以你也可以不指定。urlopen 函数会自动与目标服务器建立连接,发送 HTTP 请求,该函数的返回值是一个响应对象 Response,里面有响应头信息,响应体,状态码之类的属性。
但是,Python 提供的这个内建模块过于低级,需要写很多代码,使用简单爬虫可以考虑 Requests,Requests 在GitHub 有近30k的Star,是一个很Pythonic的框架。先来简单熟悉一下这个框架的使用方式。
安装 requests
pip install requests
GET 请求
>>> r = requests.get("https://httpbin.org/ip")
>>> r
200]> # 响应对象
>>> r.status_code # 响应状态码
200
>>> r.content # 响应内容
'{\n "origin": "183.237.232.123"\n}\n'
POST 请求
>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})
自定义请求头
这个经常会用到,服务器反爬虫机制会判断客户端请求头中的User-Agent是否来源于真实浏览器,所以,我们使用Requests经常会指定UA伪装成浏览器发起请求
>>> url = 'https://httpbin.org/headers'
>>> headers = {'user-agent': 'Mozilla/5.0'}
>>> r = requests.get(url, headers=headers)
参数传递
很多时候URL后面会有一串很长的参数,为了提高可读性,requests 支持将参数抽离出来作为方法的参数(params)传递过去,而无需附在 URL 后面,例如请求 url http://bin.org/get?key=val ,可使用
>>> url = "http://httpbin.org/get"
>>> r = requests.get(url, params={"key":"val"})
>>> r.url
u'http://httpbin.org/get?key=val'
指定Cookie
Cookie 是web浏览器登录网站的凭证,虽然 Cookie 也是请求头的一部分,我们可以从中剥离出来,使用 Cookie 参数指定
>>> s = requests.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
>>> s.text
u'{\n "cookies": {\n "from-my": "browser"\n }\n}\n'
设置超时
当发起一个请求遇到服务器响应非常缓慢而你又不希望等待太久时,可以指定 timeout 来设置请求超时时间,单位是秒,超过该时间还没有连接服务器成功时,请求将强行终止。
r = requests.get('https://google.com', timeout=5)
设置代理
一段时间内发送的请求太多容易被服务器判定为爬虫,所以很多时候我们使用代理IP来伪装客户端的真实IP。
import requests
proxies = {
'http': 'http://127.0.0.1:1080',
'https': 'http://127.0.0.1:1080',
}
r = requests.get('http://www.kuaidaili.com/free/', proxies=proxies, timeout=2)
Session
如果想和服务器一直保持登录(会话)状态,而不必每次都指定 cookies,那么可以使用 session,Session 提供的API和 requests 是一样的。
import requests
s = requests.Session()
s.cookies = requests.utils.cookiejar_from_dict({"a": "c"})
r = s.get('http://httpbin.org/cookies')
print(r.text)
# '{"cookies": {"a": "c"}}'
r = s.get('http://httpbin.org/cookies')
print(r.text)
# '{"cookies": {"a": "c"}}'
小试牛刀
现在我们使用Requests完成一个爬取知乎专栏用户关注列表的简单爬虫为例,找到任意一个专栏,打开它的关注列表。用 Chrome 找到获取粉丝列表的请求地址:zhuanlan.zhihu.com/api/columns…
然后我们用 Requests 模拟浏览器发送请求给服务器
import json
import requests
class SimpleCrawler:
init_url = "https://zhuanlan.zhihu.com/api/columns/pythoneer/followers"
offset = 0
def crawl(self, params=None):
# 必须指定UA,否则知乎服务器会判定请求不合法
headers = {
"Host": "zhuanlan.zhihu.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
}
response = requests.get(self.init_url, headers=headers, params=params)
print(response.url)
data = response.json()
# 7000表示所有关注量
# 分页加载更多,递归调用
while self.offset < 7000:
self.parse(data)
self.offset += 20
params = {"limit": 20, "offset": self.offset}
self.crawl(params)
def parse(self, data):
# 以json格式存储到文件
with open("followers.json", "a", encoding="utf-8") as f:
for item in data:
f.write(json.dumps(item))
f.write('\n')
if __name__ == '__main__':
SimpleCrawler().crawl()
这就是一个最简单的基于 Requests 的单线程知乎专栏粉丝列表的爬虫,requests 非常灵活,请求头、请求参数、Cookie 信息都可以直接指定在请求方法中,返回值 response 如果是 json 格式可以直接调用json()方法返回 python 对象。关于 Requests 的更多使用方法可以参考官方文档:docs.python-requests.org/en/master/