前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python爬虫系列之 requests: 让 HTTP 服务人类

python爬虫系列之 requests: 让 HTTP 服务人类

作者头像
渔父歌
发布2018-09-28 15:54:23
7670
发布2018-09-28 15:54:23
举报
文章被收录于专栏:数据结构笔记数据结构笔记

一、安装requests库

pip install requests

二、发起一个简单的网络请求

requests支持所有的HTTP请求,以最常用的get方法为例:

import requests


url = 'https://www.baidu.com'
response = requests.get(url)

比想象中要简单的多吧,只要把要访问的网址当作参数传递给requests.get方法,就可以获得所请求的网页。

请求成功后会返回一个Response对象,我们把这个对象叫做响应。

三、对响应的操作

  • text和 content属性 通过text属性可以查看响应的内容 #注:这里的response是前面代码块中的response, # 本系列的所有代码都会复用之前出现过的代码 print(response.text) 上面这行代码会打印出 html 页面的源代码 与text相似的属性还有content,不过content是网页内容进行二进制编码后的结果 如果你访问的是一个文件或者你想下载要访问的网页,就可以使用这个属性 url = 'https://www.baidu.com' r = requests.get(url) with open('baidu.html', 'wb+') as baidu: baidu.write(r.content) 执行上面这段代码,会把百度的首页下载到当前路径下
  • status_code http返回码 如果你想看看请求是否成功,可以打印status_code来查看返回的http状态码 print(response.status_code) http状态码有下面几种:

状态码

描述

1**

信息,服务器收到请求,需要请求者继续执行操作

2**

成功,操作被成功接收并处理

3**

重定向,需要进一步的操作以完成请求

4**

客户端错误,请求包含语法错误或无法完成请求

5**

服务器错误,服务器在处理请求的过程中发生了错误

​ 需要注意的是,如果收到5开头的http状态码。

​ 很多情况下并不是服务器发生了错误,而是服务器并不想回应你的请求,所以返回5**敷衍一下 你。

​ 这在编写爬虫代码时经常发生,如果你在爬取网页时出现了5**错误,就应该想想哪里出错了。

​ 想了解更多关于http状态码的问题可以点击文末的链接

  • apparent_encoding一劳永逸解决网页乱码问题 有些时候你可能会遇到网页乱码的问题, 这是因为 requests默认的编码方式与你所访问的网页的编码不一致。 这个时候 encoding和 apparent_encoding属性可以帮到你。 encoding表示的是响应当前的编码方式, 而apparent_encoding则是你所获取的网页要求的编码方式, 通过将apparent_encoding赋值给encoding就可以保证网页不乱码。 虽然大部分情况下网页不会出现乱码的情况,但还是强烈建议在获得一个响应后执行下面的操作: response.encoding = response.apparent_encoding

四、更加复杂的请求

你可能觉得前面讲的太简单了,不过别担心,现在才真正开始呢。

别紧张,只是复杂了一点,就像加减法到乘法一样。

有的时候我们要爬 的网站有反爬措施,这个时候简单的get请求会得到错误的响应。

因此,我们需要做点什么来跳过网站的反爬机制。

要跳过反爬机制,我们需要先了解一下网站是怎样反爬的。

大多数网站都是通过请求头(headers)和 cookie来鉴别爬虫的,cookie现在先不讲(因为用到cookie的地方一般需要登录,而登录又涉及到模拟登录的问题,所以先放这儿,等以后需要了再讲)

也有少量的网站是通过 IP来鉴别爬虫的,同一个 IP访问频率过快就会遭到封禁,这时还想继续爬就得用代理。

不过一般的服务器还是通过headers来区别爬虫与人的,所以我们只要伪造一个headers就能以假乱真,这样我们又可以开心地爬了<( ̄︶ ̄)↗GO!

这时候可能有人会问,怎么伪造headers呢?

有一个简单粗暴的方法就是直接用chrome的开发者模式把网站的请求头复制下来,不过对付一般的网站我们只需要user-agent就行(有些甚至不需要 headers)。

伪造好 headers后,headers传递给 get方法的 headers参数就可以用伪造的 headers来访问网站了

#简单粗暴的方法
headers = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Cache-Control': 'max-age=0',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Host': 'www.baidu.com',
    'Proxy-Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36',
}
#一般的方法
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36',
}

r = requests.get(url, headers=headers)
  • 带 query string的请求 现讲到这里,我们已经可以请求一些简单的网站了,然而问题并没有那么简单。 当你在浏览网页的时候,你可能会发现有的 url竟然长这样: http://zhannei.baidu.com/cse/search?q=%B9%F3%D7%E5%CE%C6%D5%C2&s=13049992925692302651&entry=1 (上面的链接是一个小说网站的站内搜索链接,我顺手拿过来用了) 百度一下,我们知道了 “?” 后面跟着的是查询字符串(query string) 服务器会根据查询字符串来返回不同的结果 这个时候聪明的你一定会想到我们可以控制 query来获得不同的响应 一个初级的版本长这样: q = '贵族纹章' s = '13049992925692302651' entry = '1' url = 'http://zhannei.baidu.com/cse/search' + '?' + 'q=' + q + '&s=' + s + '&entry=' + entry 但是这样的代码可读性实在是差,看得脑壳痛<( _ _ )> 下面给出一个更简洁的写法: url = 'http://zhannei.baidu.com/cse/search?q={}&s={}&entry={}'.format(q, s, entry) 这样已经很简洁了,但是仔细分析一下,我们发现返回的结果是由 q、s、entry三个变量共同决定的。 也就是说 q、s、entry三个变量是有某种联系的,所以我们需要把这三个变量看作一个对象 这时候最好的方法是,用一个字典表示它们(刚好 requests有 params参数来接收一个 dict作为 query string): params = { 'q': '贵族纹章', 's': '13049992925692302651', 'entry': '1', } url = 'http://zhannei.baidu.com/cse/search' r = requests.get(url, params=params)
  • post 方法提交表单 现在我们就可以轻松地爬很多网页了,但是上面讲到的方法只适用于用 get 方法访问的网页。 如果碰到要登录或者需要提交表单的网页就束手无策了,遇到这种情况 post 方法就排上用场了。 post 方法的使用和 get 方法一样,也可以传入 headers 参数。 唯一不同的就是 post 方法用 data 来接收要提交的表单数据,data 要求是字典格式 data 的键对应 html 中表单的 name,举例如下: 示例网页:<!DOCTYPE html> <html> <head> <title>注册</title> <meta charset="utf-8"> </head> <body> <form action="#" method="post"> <div class="row"> <span class="col s4">username:</span><input type="text" name="username"> </div> <div class="row"> <span class="col s4">password:</span><input type="password" name="password"> </div> <div class="row"> <button class="col s4 center" type="submit">提交</button> </div> </form> </body> </html>#这个网页可以返回 post方法提交的表单数据 url = 'http://203.195.204.124/post' #构造 data 字典 username 、password 分别和上方网页中的 username 和 password 对应 data = { 'username': 'geebos', 'password': '123456', } r = requests.post(url, data=data) #也可以传入 headers 参数 r = requests.post(url, data=data, headers=headers) print(r.text) '''返回的内容(r.text):{"username": "geebos", "password": "123456"}'' 当然,真正的 post 请求比这个例子要复杂一些,至少密码是经过加密再进行传输的

五、高级用法 session会话

在一些需要登录的网站中我们需要跨请求保持 cookie,但是前面所讲的 post和 get方法不会保存 cookie。

虽然我们可以通过提取 cookie给 headers参数来保持 cookie,但这种方法有个缺点就是必须要手动提取 cookie,要是碰到上百个登录... ...

幸好 requests库的 Session类可以跨请求保持 cookie,省去了我们的体力劳动。

session的使用很简单,下面通过几行代码来演示 session的使用:

#获得一个 session实例 想要跨请求保持 cookie必须在同一个 session下调用方法
session = requests.Session()

url = 'https://www.baidu.com'

#get方法
r = session.get(url)
#post方法
r = session.post(url, data=data)

六、总结

  • get请求 url params headers
  • post请求 url params headers data
  • session会话 要跨请求保持 cookie必须在同一个 session实例下调用方法

有问题欢迎评论

http状态码:HTTP状态吗|菜鸟教程

下一篇:python爬虫系列之 requests实战:用 requests库下载网页和图片

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.05.18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、安装requests库
  • 二、发起一个简单的网络请求
  • 三、对响应的操作
  • 四、更加复杂的请求
  • 五、高级用法 session会话
  • 六、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档