文章目录

  • 0 前情提要
  • 1 进行简单请求
  • 2 添加 GET 参数
  • 3 添加 POST 数据
  • 3.1 application/x-www-form-urlencoded 的方式
  • 3.2 multipart/form-data 的方式
  • 4 传递 cookie
  • 5 进阶:设置“客户端”
  • 6 进阶:设置代理
  • 7 进阶:携带证书
  • 8 总结


Python 有非常多网络请求相关的库,这里我只介绍一些我自己用过的库,但不一定是最好的库。
我会按照“任务”的方式来组织这篇文章。

0 前情提要

Python 爬虫科普:爬虫是什么?该怎么入门?

1 进行简单请求

有一些网站没有身份校验的要求,通过最简单的网络请求就能拿到你要的结果,例如上篇文章里的这个例子:

from urllib import request # 用于发起网络请求的库

response = request.urlopen("https://api.ipify.org") # 任务一:发起网络请求
IP = response.read().decode('utf8') # 任务二:处理数据
print(IP) # 任务三:保存或展示数据

2 添加 GET 参数

如果还不了解 GET、POST 等请求方法的概念,还请先通过百度等方式了解一下。
GET 参数往往就在请求的链接中,通过浏览器的地址栏即可了解。

from urllib import parse # 用于处理参数
from urllib import request # 用于发起网络请求的库

searchURL = 'https://www.baidu.com/s?' # 请求地址
# GET 参数
para = {
	'ie': 'utf-8',
	'wd': 'Python 爬虫'
}

# 对 GET 参数进行 URL 编码
getPara = parse.urlencode(para)

# 发起请求
response = request.urlopen(searchURL + getPara)
print(response.read().decode('utf8'))

3 添加 POST 数据

通过 POST 方法提交数据,通常见于用户注册登录、提交一些表单数据。在开始之前你需要确保:

POST 有多种方式( Content-Type ),其中最常见的还是 application/x-www-form-urlencodedmultipart/form-data 两种。

3.1 application/x-www-form-urlencoded 的方式

POST 请求通常用于登录动作,因此你可以找一个网站的登录页面进行练手,例如知乎。
挑选练手网站时请注意,如果你在网页的表单里看到一个 csrf_token 类似的隐藏字段,那么请你先换一个其他的网站,这个 csrf_token 的处理目前是超纲的。

使用 POST 方法进行请求时,默认会按照 application/x-www-form-urlencoded 的方式进行参数的传递,调用也相对简单。
为了传递 POST 参数,就不能简单地 urlopen 了,你需要使用 request 对象来描述你的请求。

from urllib import request

loginURL = '...某个登录链接...'
email = '邮箱'
password = '密码'


data = {
    'user': email, # 这里的 data 字段,具体需要看你练手网站上表单各字段的 ID
    'pw':password
}

Request = request.Request(loginURL, \
                          method = 'POST', \
                          data = bytes(urllib.parse.urlencode(data), encoding = 'utf-8'))
# Request 对象包含了一个网络请求所需的所有信息,除了链接地址,还有请求方法、请求参数、其他 header 
# method 参数说明请求的方式是 POST
# data 参数规定 POST 请求的数据,bytes() 函数将 string 使用规定编码进行二进制编码
                                 
response = request.urlopen(Request) # 完成请求
result = response.read().decode('utf-8') # 读取结果
print(result)

关于 Request 对象的深入介绍,可以参考 官网说明

3.2 multipart/form-data 的方式

需要通过 POST 上传文件的时候,网站就只能使用 multipart/form-data 了,实际上作为爬虫,POST 请求通常只会用在登录、提交搜索之类的操作中,所以使用这个请求方式的机会并不多见。当然你也可以通过 requests

4 传递 cookie

浏览器里的 cookie 大概就是对话的“环境”,这篇教程 对 cookie 进行了大致的介绍。
实际上“登录”操作的结果,就是返回了一个凭证,当你发起网络请求时,带上这个凭证,就证明了你是登录的用户。而这个“凭证”就存放在 cookie 里。
所以模拟登录最重要的,实际上是获取 cookie,并且在后续的请求中把相应的 cookie 带上,从而模拟一个“对话环境”。

from urllib import request # 用于处理网络请求
from http import cookiejar # 用于处理 cookie

cookies = cookiejar.CookieJar() # 设置一个 cookie 容器,可以对容器中的信息进行读写

opener = request.build_opener(request.HTTPCookieProcessor(cookies), request.HTTPHandler(), request.HTTPSHandler())
# build_opener() 的参数是一些“处理器”,返回一个类似“浏览器对象”,这些“处理器”为返回的“浏览器对象”赋予能力
# HTTPCookieProcessor 是 cookie 的处理器,我们使用了 cookies 容器进行初始化,后续的所有 cookie 均可以通过这个变量进行读写
# HTTPHandler 是 http 请求的处理器
# HTTPSHandler 是 https 请求的处理器

userRequest = urllib.request.Request('请求地址', ...) # 根据具体请求的情况组建请求
response = opener.open(userRequest) # 使用之前生成的“浏览器对象”进行请求

print(cookie) # 此次请求生成的 cookie 已经放到了 cookie 里

通过官网说明,你可以了解 cookiejar 的具体用法;
想了解 build_opener 相关的详细介绍,也可以看官网说明

还有一种偷懒的情况,其实你可以利用浏览器里已经存在的 cookie 信息,从而不用模拟登录,就可以用一个“用户身份”,进行网站的访问。
也有一个 Python 库,就是来获取浏览器中 cookie 的,这个库不是原生提供的,可以通过 pip 直接安装。

pip install browsercookie # 如果你不了解 pip,可以去查一查 pypi 相关的教程

使用起来也比较简单

import browsercookie

# 通过最简单的方式获取 Chrome 里的 cookie
chrome_cookie = browsercookie.chrome()
# 另外还支持 firefox 和 Safari,可以通过 help(browsercookie) 查看
# chrome_cookie 是一个 cookiejar 对象

# 复杂一点的语法
Chrome = browsercookie.Chrome()
file_path = Chrome.find_cookie_files() # Chrome 的 cookie 存放路径
chrome_cookie = Chrome.get_cookies() # 获取 cookie

5 进阶:设置“客户端”

所谓“客户端”,就是发起请求的那个“端”,例如我电脑上的 Chrome 就是 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36

这个“客户端段”在发起请求时,是作为一个 header 传递出去的,字段是 User-Agent 。在上一节中提到的 Content-Type 实际上也是 header 的一个。

Python 的 urllib 库发起的请求,默认使用的 User-Agent 是 “python”,有一些爬虫框架也会使用自己的 User-Agent ,例如 “scrapy”。有一些网站会根据 User-Agent 制定一些反爬虫策略,爬虫往往也会遵循网站的一些规定,比方你可以看看知乎对爬虫的策略 因此,你可以修改这个 User-Agent 做一些无伤大雅的事情。同样,网上也有关于设置“客户端”的详细教程

6 进阶:设置代理

一些情况下,需要使用代理才能访问网站,Python 也提供了便捷的工具,实际上就是为我们的“浏览器对象”再赋予一个新的“处理器”。
拿 socks5 代理为例进行说明:

import sockshandler # 引入 socks 处理器
import socks # socks 是一个更低层次的接口封装
# 如果引入时出现问题,请现在命令行 pip install PySocks

opener = build_opener(sockshandler.SocksiPyHandler(socks.SOCKS5, "127.0.0.1", 1080), ...) # 根据需要添加其他 handler
# SocksiPyHandler 即 socks 代理的处理器
# socks.SOCKS5 说明代理类型是 socks5
# 127.0.0.1 是代理地址
# 1080 是代理端口

userRequest = ... # 组装 Request
response = opener.open(userRequest) # 进行网络请求

# ... 结果处理

如果感兴趣,可以通过 官方说明sockshandler.SocksiPyHandler 进行更深入的了解。
关于 HTTP 和 HTTPS 代理,这篇教程 说得很好,大家可以看看

7 进阶:携带证书

如果大家还有印象,最早的时候 12306 需要下载一个证书后才能正常访问,而且必须使用 IE 浏览器。在一些公司内网安全防控要求也很高,需要在员工电脑上安装证书才可以进行某些网页请求,其实和 12306 的做法是相似的。
使用 Python 进行这些页面的访问时,就需要把自己的证书带上。

这里又涉及到非常多的知识点,对于我一个非计算机出身的人来讲,还是花了很长的时间来学习

  • 首先关于 HTTPS
  • 了解以上概念后,你可能需要对数字证书有更清晰的认识,比方说这篇,从而把你的证书转成 Python 可以识别的格式

Python 里 urllib 还是通过“浏览器对象”和“处理器”来夹带证书信息的。

from ssl import SSLContext # 处理 https 请求环境,例如证书
from urllib import request

# 设置证书环境
sslContext = SSLContext()
sslContext.load_cert_chain(certfile = '证书路径/证书.pem')

opener = request.build_opener(request.HTTPCookieProcessor(context = sslContext), ...) # 添加所有必要的处理器
# 将证书环境赋予处理器

userRequest = ... # 组装 Request
response = opener.open(userRequest) # 进行网络请求

# ... 结果处理

8 总结

一篇文章其实只是一个切片,这篇文章里的外链多到令人发指,“看完”这篇文章所需要花费的时间是很长的。
其实也正说明了爬虫为什么对非计算机专业的同学来讲,为啥比较不好入门,因为需要的预备知识的确比较多。
但是只要有耐心,这些知识还是能够掌握的。