Python爬虫从入门到精通(2):requests库详解,cookie操作与实战

Python的第三方requests库是基于urllib编写的,但是比urllib库强大,非常适合爬虫的编写,可以帮我们节省很多工作。在

Python爬虫从入门到精通(1): 爬虫原理, urllib库介绍及5个适合新手练手的爬虫

我们已经介绍了urllib库用法的用法,比如当我们需要向一个url发送get参数或post数据时,我们先要对参数或数据进行urlencode编码,再用urllib.request.Request方法构建一个request_url对象加入参数和数据,最后使用request.urlopen方法打开构建好的request_url。这个操作requests库用一行代码就可以实现了。在打开一个url的时候,就能发送get参数或post数据。同时requests库还简化了对cookie的操作,比如请求头里带上cookie或者维持网站会话都非常方便。事实上自从用上了requests库,我已经不怎么用urllib库了。今天小编我就来详细介绍下requests库的基本用法和如何操作cookie,并用几个具体实例演示下如何利用requests库开发爬虫。

requests库的安装及第一个requests爬虫

安装requests库只需要在终端中输入pip install requests。为了确保requests库已经成功安装,你可以用它写个非常简单的爬虫,爬取百度的首页(见下面代码)。如果返回的response的状态码status_code是200,那么你的requests库就安装成功了。你还可以选择打印response.text或response.content查看reponse的具体内容。

>>>importrequests

>>> response = requests.get("https://www.baidu.com")

>>>print(response.status_code)

200

>>>print(response.text)

>>>print(response.content)

response.text和response.content的区别在于:

requests库支持的请求方法

requests库支持多种HTTP请求方法,然而最常用的只有get和post方法。小编我其它方法也基本不用。

importrequests

requests.get("http://xxxx.com/")

requests.post("http://xxxx.com/post",data= {'key':'value'})

requests.put("http://xxxx.com/put",data= {'key':'value'})

requests.delete("http://xxxx.com/delete")

requests.head("http://xxxx.com/get")

requests.options("http://xxxx.com/get")

发送带参数的get请求

使用requests发送带参数的get请求非常简单,在get方法里设置字典格式的params参数可。下例中,我们向百度的搜索页面发送了两个参数,关键词wd和每页显示的条目数pn。如果你此时打印response.url, 你会发现requests方法已经自动完成了url的拼接,实际请求的url已经变成了https://www.baidu.com/s?wd=python&pn=10。

importrequests

params = {

"wd":"python","pn":10,

}

response = requests.get('https://www.baidu.com/s',params=params)

print(response.url)

print(response.text)

发送带数据的post请求

使用requests发送带参数的post请求也非常简单,完全不像urllib那样先需要对数据进行urlencode编码才能发送,我们只需要在post方法里设置data参数即可。下面代码模拟了用户的登录。如果响应失败,reponse的raise_for_status方法会打印错误代码. 如果响应成功(状态码为200), raise_for_status会返回一个空值(None.)

importrequests

post_data = {'username':'value1','password':'value2'}

response = requests.post("http://xxx.com/login/",data=post_data)

response.raise_for_status()

post也可以用于上传文件,示例代码如下所示:

>>>importrequests

>>> url ='http://httpbin.org/post'

>>> files = {'file':open('report.xls','rb')}

>>> r = requests.post(url,files=files)

设置与查看请求头(headers)

很多网站都有反爬机制,如果一个请求不携带请求头headers, 很可能被禁止访问。我们可以按如下方式设置请求头。你也可以通过打印response.headers查看当前请求头。

importrequests

headers = {

"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/"

"537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

}

response1 =requests.get("https://www.baidu.com",headers=headers)

response2 =requests.post("https://www.xxxx.com",data={"key":"value"},

headers=headers)

print(response1.headers)

print(response1.headers['Content-Type'])

print(response2.text)

设置代理Proxy

有的网站反爬机制会限制单位时间内同一IP的请求次数,这时我们可以通过设置IP proxy代理来应对这个反爬机制。requests里设置proxy也非常简单,如下面代码所示。

importrequests

proxies = {

"http":"http://10.10.1.10:3128",

"https":"http://10.10.1.10:1080",

}

requests.get("http://example.org",proxies=proxies)

Cookie的获取和添加

有时候我们需要爬取登录后才能访问的页面,这时我们就需要借助cookie来实现模拟登陆和会话维持了。那么服务器是如何知道我们已经登录了呢?当用户首次发送请求时,服务器端一般会生成并存储一小段信息,包含在response数据里。如果这一小段信息存储在客户端(浏览器或磁盘), 我们称之为cookie。如果这一小段信息存储在服务器端,我们称之为session(会话)。这样当用户下次发送请求到不同页面时,请求自动会带上cookie,这样服务器就知道用户之前已经登录访问过了。

然而并不是访问所有的页面时服务器都会生成自动cookie或session。那么问题来了? 我们如何知道发送首次请求后服务器是否生成了cookie呢? 这时我们可以直接通过打印response.cookies来获取查看cookie内容。

下例中当我们发送请求到中国政府网时,我们可以看到返回的reponse里的cookies是个空的RequestsCookieJar[],里面没有任何cookie。然而当我们发送请求到百度时,你可以看到百度已经生成了一个名为BAIDUID的cookie,放在RequestsCookieJar[]里了。你还可以通过打印response.cookies['BAIDUID']来打印BAIDUID的内容。

>>>importrequests

>>> response = requests.get(""http://www.gov.cn/2018-09/29/content_5326686.htm")

>>>print(response.cookies)

>>> response1 = requests.get("https://fanyi.baidu.com")

>>>print(response1.cookies)

'for .baidu.com / >, ] >'

>>>print(response1.cookies['BAIDUID'])

6BA7A5263775F7D67E0A4B88BF330717:FG=1

如果你希望在发送请求时添加某些cookie, 最简单的方法就是设置cookies参数。

importrequests

headers = {

"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/"

"537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

}

cookies = {"cookie_name":"cookie_value",}

response = requests.get("https://www.baidu.com",headers=headers,cookies=cookies)

然而更专业的方式是先实例化一个RequestCookieJar的类,然后把值set进去,最后在get,post方法里面指定cookies参数。代码如下所示:

>>>importrequests

>>>fromrequests.cookiesimportRequestsCookieJar

>>> cookie_jar = RequestsCookieJar()

>>> cookie_jar.set("BAIDUID","4EDT7A5263775F7E0A4B&F330724:FG=1",domain="baidu.com")

>>> response = requests.get("https://fanyi.baidu.com/",cookies=cookie_jar)

Session会话的维持

session与cookie不同,因为session一般存储在服务器端。session对象能够帮我们跨请求保持某些参数,也会在同一个session实例发出的所有请求之间保持cookies。为了保持会话的连续,我们最好的办法是先创建一个session对象,用其打开一个url, 而不是直接使用requests.get方法打开一个url。每当我们使用这个session对象重新打开一个url时,请求头都会带上首次产生的cookie,实现了会话的延续。代码如下图所示。

importrequests

headers = {

"content-type":"application/x-www-form-urlencoded;charset=UTF-8",

"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) ",

}

#设置一个会话session对象s

s = requests.session()

resp = s.get('https://www.baidu.com/s?wd=python',headers=headers)

#打印请求头和cookies

print(resp.request.headers)

print(resp.cookies)

# 利用s再访问一次

resp = s.get('https://www.baidu.com/s?wd=python',headers=headers)

#请求头已保持首次请求后产生的cookie

print(resp.request.headers)

print(resp.cookies)

输出结果如下所示:

{'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) ', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'content-type': 'applicat

ion/x-www-form-urlencoded;charset=UTF-8'}

, , ]>

{'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) ', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'content-type': 'applicat

ion/x-www-form-urlencoded;charset=UTF-8', 'Cookie': 'BIDUPSID=761555A95ECB9986056F34E679D317CC; PSTM=1538225799; BD_NOT_HTTPS=1'}

requests实战: 爬取百度搜索前20个搜索页面的标题和链接

我们的总体思路是使用requests发送带参数的get请求,其中wd为关键词,pn为每页显示的搜索条目数(默认为10条每页), 关键词由命令终端输入。我们使用BeautifulSoup解析出百度的跳转链接,然后直接访问那些链接,打印出页面的title和url。

我们新建一个文件baidu_spider.py,添加如下代码:

# coding:utf-8

importrequests

importsys

frombs4importBeautifulSoupasbs

importre

headers = {

'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '

'Chrome/57.0.2987.133 Safari/537.36',

}

defmain(keyword):

file_name ="{}.txt".format(keyword)

#创建空文件

f =open(file_name,'w',encoding="utf-8")

f.close()

forpninrange(,20,10):

params = {"wd": keyword,"pn": pn,}

r = requests.get(url='http://www.baidu.com/s',params=params,headers=headers)

soup = bs(r.content,"html.parser")

urls = soup.find_all(name='a',attrs={'href': re.compile(('.'))})

#抓取百度搜索结果中的a标签,其中href是包含了百度的跳转地址

foriinurls:

if'www.baidu.com/link?url='ini['href']:

#抓取跳转后的页面

a = requests.get(url=i['href'],headers=headers)

soup1 = bs(a.content,"html.parser")

title = soup1.title.string

withopen(keyword +'.txt','r',encoding="utf-8")asf:

ifa.urlnot inf.read():

f =open(keyword +'.txt','a',encoding="utf-8")

f.write(title +'\n')

f.write(a.url +'\n')

f.close()

if__name__ =='__main__':

iflen(sys.argv) !=2:

print('no keyword')

print('Please enter keyword')

sys.exit(-1)

else:

main(sys.argv[1])

print("下载完成。")

当我们在终端输入python baidu_spider.py "django"时,大约等待3分钟,你就可以看到生成的django.txt里包含20条搜索记录(标题与链接), 效果如下图所示:

小结

我们详细介绍了如何使用requests库发送带参数的get请求,带数据的post请求,如何设置headers和代理,如何操作cookie,以及如何维持会话。我们还用requests库开发一个非常有用的爬虫,可以用来爬取baidu搜索前20条搜索记录的标题和链接。希望本文对大家有所帮助。

大江狗

2018.9.29

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180929G20XQR00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动