upyter 是一个简易的,方便的写Python代码的工具包,requests是Python里非常好用的用来发送 http 请求的包。
开始学习本教程之前,请确保你已经安装了Python,并且安装了Python包 jupyter 和 requests 了。如果没有,那请参照以下教程进行安装:
1. jupyter的简单使用
老规矩:Windows键+X键
选择 命令提示符。
打开了命令提示符,那么我们输入命令: jupyter notebook
回车。
接着你的浏览器会自动打开下面的界面:
注:
如果没有自动打开浏览器却显示了一个网址在窗口里面,那么是你电脑没有设置默认浏览器或者默认浏览器设置错误导致的;
如果浏览器打开了网页却不显示任何东西,无法正常使用,请检查你的浏览器的版本是否比较陈旧,推荐使用Firefox、Chrome、QQ浏览器等使用非IE内核或高等级IE内核的浏览器。
接着我们点击网页右边的 new,选择 Python3。(我的jupyter多了个Python2的选项,那是因为我自己给jupyter配置了Python2,默认情况下,只有你当前的Python版本的文件选项。)
选择了创建文件之后,浏览器打开了一个新的界面,这就是我们的代码编辑界面啦,从此以后就可以开开心心写代码了。
我们在下面的In [ ]:
那里输入我们的第一个程序的第一条语句:
print("Hello World")
然后点击画面上方的Run按钮,就运行我们的程序啦。效果如图:
Requests: HTTP for Humans
这是 requests 的 slogan。非常简单明了,我觉得翻译成中文大概是:给人使用的 HTPP 请求库。
根据我个人经验来说,看到过很多初学者(也包括曾经的我),都跟着网上很老的爬虫教程,使用urllib、urllib2来发起请求。这样的结果是什么?不仅写代码效率非常低下,而且代码量比requests多得多,同时代码也难以理解。
这几个过时的库一点也不友好,简直不像是给人使用的。
所以从遇到requests的第一天起,我就永远地抛弃了urllib之类的库了。
requests的作者,是一位非常帅气的摄影师小哥。目前requests在GitHub上已经获得了32062个Star。
下面我们来学习requests的基本使用。
2. import requests并发起一个请求
我们在jupyter的新的一个输入里面,键入下面的代码并点击运行:
import requests
print(requests.get("https://www.baidu.com"))
注意:括号都是英文的括号哦
运行结果:
import requests
: 代码文件里面引入requests这个包以便后面代码的使用
print(requests.get("https://www.baidu.com"))
:用requests向百度首页发起一个get请求,并打印出请求的结果(response对象)。
这就已经完成了我们使用浏览器打开百度首页的过程了。那为什么我们没看到网页也没看到html呢?我们把代码改成这样再运行一次:
import requests
response = requests.get("https://www.baidu.com")
print(response.status_code)
print(response.content)
运行结果:
第一行的200,是我们这个请求的HTTP状态码,200表示请求成功,关于状态码前面已经讲解过了:爬虫入门教程③— 必备知识基础(二)HTTP请求简介。
第二行开始就是输出的我们获取到的百度首页的HTML代码的二进制字符串,b'xxxxx'
表示这个字符串是二进制的。
那我们怎么把二进制结果改成我们看得懂的中文结果呢?我们只需要对响应的content(二进制)进行一次解码,常见的解码方式有gbk
, utf-8
。
Windows文件用的是gbk编码,有一些比较古老的网页也是用的gbk编码。现在大部分的网页都是用的 utf-8 的编码了。
我们怎么知道网页用的哪个编码呢?一般是看meta信息里面charset的值:
当然也可以猜,不报错,不乱码,那就对了。
于是我们在输出二进制响应后面加上.decode('utf-8')
,把二进制字符转换成字符串:
import requests
response = requests.get("https://www.baidu.com")
print(response.status_code)
print(response.content.decode('utf-8'))
输出如下:
现在就能看懂了,我们成功打开了百度的首页!
是的,requests发起一个请求就是这么简单。
要发起 post 请求,也同样简单
import requests
form = {'username': 'admin','password': 'admin123456'}
response = requests.post("https://www.baidu.com", data=form)
print(response.content.decode('utf-8'))
这就向百度首页,发起了一个post请求,并且带上了两个参数,参数名是username和password,值是admin和admin123456。post请求我们一般用于对网页发送数据,比如登录,发送图片、文件等等。如果请求方式弄错了,很可能得不到正确的响应的哦。
3. requests.session的使用
这里要介绍一下cookie:
Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。
cookie就相当于一个令牌,你拿着它去访问网站,网站就能辨别你是谁了。所以如果你登录了,你去访问其他需要登录的网页,都可以直接访问,因为浏览器在你访问的时候,默认会带上cookie。cookie的添加、删除、更新是在服务器返回的响应里获取到的。
requests.get()
是发送请求常用的一个办法。它不能做到的是对cookie的持久化: 上一个请求获取到的cookie,没办法简单地传递到下一个请求去,这样两个requests.get()
请求之间没有办法产生联系。如果是对于需要登录的网站来说,这是毁灭性的,我们会一直卡在登录界面。
下面要引入的就是requests的session。它能够自动管理cookie,也能够进行cookie的持久化。用法也很简单:
import requests
http_session = requests.session()
response = http_session.get("https://www.baidu.com")
print(response.content.decode('utf-8'))
我们定义了一个http_session
用来作为我们的session。然后我们使用这个http_seesion
发出的每个请求,都会自动带上cookie,也会自动处理网站服务器返回的对cookie的操作。
这些过程对我们不可见,而我们只需要使用就好了!简直完美!
4. 把从浏览器获取到的cookie添加到session里来绕过登录
注:此小节为进阶教程,不理解可暂时跳过。
首先补充一下cookie的知识:
-
原因:http请求是无状态的,也就是说,你的每一次请求,网站服务器都会认识是一次新的请求。
-
问题:既然每一次请求都是新的请求,那么网站识别用户就遇到困难了:一个网站需要服务于多个用户,每个用户的需要呈现的内容可能是不同的。如果每次请求都是全新的,服务器会不知道是谁发过来的,进而就可能造成一个混乱的局面,把A的消息发给了B,C的邮件给了A等等。
-
解决方案:服务器如果需要识别你的身份,那它就给你发送一个或多个cookie(如果不需要对你进行特异性识别,那就没必要设置cookie了),之后你的每个请求默认会带上服务器设置的cookie(浏览器自动处理)。由于服务器给每个用户的分配的cookie的值是不同的,那服务器就可以轻松地通过cookie的值来识别用户了。
-
拓展:既然服务器是通过cookie这个令牌识别你是谁的,那么只要你的请求带上了任意一个人的cookie去访问服务器,那么服务器就会认为你就是那个人。所以在以前有中间人攻击这个事情,黑客就是通过拦截你的请求,找到你的cookie,自己伪装成你,然后帮他发广告或者是进行一些其他的危险操作以获得利润。
如果我们需要爬取一个需要登录的网站,但是他的登录流程非常麻烦,甚至需要输入验证码。我们有没有什么比较轻便的办法来解决这个问题呢?
当然有:我们在浏览器上登录了,然后把浏览器上的网站发送给你的cookie,按照格式添加到我们的session里面,那么我们就无需登录,成功伪装成了浏览器里面的自己的账号了,进而可以直接进行爬取了(每个请求带上cookie,服务器就会认为我们是已经登录过了)。
怎么获取浏览器的cookie呢?
F12打开调试模式,然后选中NetWork(网络)。接着鼠标点到网页上去,按F5刷新界面。我们马上可以看到在调试窗口里面的列表有一个接一个的请求出现了,我们找到第一个请求(通常是第一个,具体请看请求的网址),点击一下,就显示出了这个请求的具体信息了。
接着再找到Request Header里面的Cookie:
在我的截图里面,百度给我发送了非常多的cookie,你可能没这么多,但是也不影响,毕竟这只是个示例。
- 接着我们把所有的cookie复制下来。
- 每一条cookie是以
;
隔开的,所以我们先以;
把这些cookies分开,分割为一条条的cookie。 - 对于每条cookie我们再以第一个
=
把一条cookie分为 name 和 value 两个部分。 - 然后我们把这些key-value的数据,添加到一个dict里面
- 最后把cookie添加到 http_session 的cookies里面。
举个例子,复制下来的cookies字符串为
"sessionid=124586245;name=pikaqiu;FDS=fdsa=okok;how=areyou"
首先我们以;
切割这个字符串得到了下面这几条cookie
"sessionid=124586245"
"name=pikaqiu"
"FDS=fdsa=okok"
"how=areyou"
然后我们再把这几条cookie转换成requests能够接受的格式:
cookies = {
'sessionid': '124586245',
"name": "pikaqiu",
"FDS": "fdsa=okok",
"how": "areyou",
}
最后再把这个cookie添加到requests提供的http_session里面,之后这个session就会自动为我们处理cookie了,包括每个请求发送cookie,修改和删除cookie的信息。
下面以上图的百度举个例子,下面就是采用了我自己的cookie访问百度的例子:
import requests
http_session = requests.session()
cookies = {'BAIDUID': 'CC97B75E17BC78:FG=1',
'BIDUPSID': 'CC97B75E17FE0BEEBC78',
'PSTM': '15700',
'BDSFRCVID': 'th-sJeC626F0ZTQA',
'H_BDCLCKID_SF': 'tJPjVC0yt',
'ispeed_lsm': '2',
'H_PS_645EC': '00e6qFET6oh4QC9Q',
} # 为了减少篇幅,我删掉了后面的几个cookie,你们可不能偷懒哦~
requests.utils.add_dict_to_cookiejar(http_session.cookies, cookies)
response = http_session.get("https://www.baidu.com")
print(response.content.decode('utf-8'))
通过把浏览器的cookie添加到程序里面,然后用程序来进行访问,我们就可以节约用程序登录的步骤,专心进行我们其他的操作了。这个办法同样适用于一些不需要登录,但是对cookie有要求的网站。