本文将介绍网络数据采集的基本原理:
- 如何用Python从网络服务器请求信息
- 如何对服务器的响应进行基本处理
- 如何以自动化手段与网站进行交互
- 如何创建具有域名切换、信息收集以及信息存储功能的爬虫
学习路径
爬虫的基本原理
所谓爬虫就是一个自动化数据采集工具,你只要告诉它要采集哪些数据,丢给它一个 URL,就能自动地抓取数据了。其背后的基本原理就是爬虫程序向目标服务器发起 HTTP 请求,然后目标服务器返回响应结果,爬虫客户端收到响应并从中提取数据,再进行数据清洗、数据存储工作。
以下截图来自 掘金小册
基于 Python 实现微信公众号爬虫对《图解HTTP》的总结
Python的一些基础爬虫模块
urllib
Python 提供了非常多工具去实现 HTTP 请求,但第三方开源库提供的功能更丰富,你无需从 socket 通信开始写,比如使用Pyton内建模块 urllib 请求一个 URL
这里我们先操练起来,写个测试爬虫
from urllib.request import urlopen//查找python的urllib库的request模块,导出urlopen函数
html = urlopen("http://jxdxsw.com/")//urlopen用来打开并读取一个从网络获取的远程对象
print(html.read())
然后,把这段代码保存为`scrapetest.py`,终端中运行如下命令
python3 scrapetest.py
这里会输出http://jxdxsw/
这个网页首页的全部HTML代码
鲸鱼注
:
Python 3.x中urllib分为子模块:
- urllib.request
- urllib.parse
- urllib.error
- urllib.robotparser
urllib是python的标准库,它能够:
- 从网络请求数据
- 处理cookie
- 改变 请求头和用户代理 等元数据的函数
更多查看python官方文档
标准示例
import ssl
from urllib.request import Request
from urllib.request import urlopen
context = ssl._create_unverified_context()
# HTTP请求
request = Request(url = "http://jxdxsw.com",
method="GET",
headers= {"Host": "jxdxsw.com"},
data=None)
# HTTP响应
response = urlopen(request, context=content)
headers = response.info() #响应头
content = response.read() #响应体
code = response.getcode() #状态码
- 这里的请求体 data 为空,因为你不需要提交数据给服务器,所以你也可以不指定
- urlopen 函数会自动与目标服务器建立连接,发送 HTTP 请求,该函数的返回值是一个响应对象 Response
- 里面有响应头信息,响应体,状态码之类的属性。
requests
Python 提供的urllib内建模块过于低级,需要写很多代码,使用简单爬虫可以考虑 Requests
安装 requests
pip3 install requests
GET请求
>>> r = requests.get("https://httpbin.org/ip")
>>> r
<Response [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 = request.Session()
s.cookies = requests.utils.cookiejar_from_dict({"a":"c"})
r = s.get('http://httpbin.org/cookies')
print(r.text)
# '{"cookies": {"a": "c"}}'
实例
使用Requests完成一个爬取知乎专栏用户关注列表的简单爬虫
以一起学习爬虫这个专栏为例,打开关注列表关注列表
用 Chrome 找到获取粉丝列表的请求地址
https://zhuanlan.zhihu.com/ap...
然后我们用 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 对象
python-requests 文档