POST请求
POST是HTTP协议的请求方法之一,也是比较常用到的一种方法,用于向服务器提交数据。先介绍进行post请求的一些准备工作,然后举一个例子,对其使用以及更深层概念进行详细的的剖析。
POST请求的准备工作
既然要提交信息给服务器,我们就需要知道信息往哪填,填什么,填写格式是什么?带这些问题,我们往下看。
同样提交用户登录信息(用户名和密码),不同网站可能需要的东西不一样,比如淘宝反爬机制较复杂,会有其它一大串的额外信息。这里,我们以豆瓣为例(相对简单),目标是弄清楚POST是如何使用的,复杂内容会在后续实战部分与大家继续分享。
抛出上面像淘宝一样需要的复杂信息,如果仅考虑用户名和密码的话,我们的准备工作其实就是要弄明白用户名和密码标签的属性name是什么,以下两种方法可以实现。
- 浏览器F12查看element获取
- 也可以通过抓包工具Fiddler获取,fiddler的下载地址https://www.telerik.com/download/fiddler
如果我们需要name该如何做呢
1. 浏览器F12
通过浏览器F12元素逐层查看到(我是用的Chrome),邮箱/手机号标签的name="form_email", 密码的标签name="form_email",如下图红框所示。
image.png
但要说明的是,两个标签的name名称并不是固定的,上面查看的name名称只是豆瓣网站定义的,不代表所有。其它的网站可能有会有不同的名称,比如name="username",name="password"之类的。因此,针对不同网站的登录,需要每次查看name是什么。
2. 通过fiddler抓包工
image.png推荐使用fiddler工具,非常好用。爬虫本身就是模拟浏览器工作,我们只需要知道浏览器是怎么工作的就可以了。
fiddler会帮助我们抓取浏览器POST请求的所有内容,这样我们得到了浏览器POST的信息,把它填到爬虫程序里模拟浏览器操作就OK了。另外,也可以通过fiddler抓到浏览器请求的headers,非常方便。
安装fiddler的小伙伴们注意:fiddler证书问题的坑(无法抓取HTTPs包),可以通过Tools —> Options —>HTTPS里面打勾Decrypt HTTPS traffic修改证书来解决。否则会一直显示抓取 Tunnel 信息包...
好了,完成了准备工作,我们直接上一段代码理解下。
POST请求的使用
# coding: utf-8
import urllib.request
import urllib.error
import urllib.parse
# headers 信息,从fiddler上或你的浏览器上可复制下来
headers = {'Accept': 'text/html,application/xhtml+xml,
application/xml;q=0.9,image/webp,image/apng,
*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3;
Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko)Chrome/48.0
.2564.48 Safari/537.36'
}
# POST请求的信息,填写你的用户名和密码
value = {'source': 'index_nav',
'form_password': 'your password',
'form_email': 'your username'
}
try:
data = urllib.parse.urlencode(value).encode('utf8')
response = urllib.request.Request(
'https://www.douban.com/', data=data, headers=headers)
html = urllib.request.urlopen(response)
result = html.read().decode('utf8')
print(result)
except urllib.error.URLError as e:
if hasattr(e, 'reason'):
print('错误原因是' + str(e.reason))
except urllib.error.HTTPError as e:
if hasattr(e, 'code'):
print('错误编码是' + str(e.code))
else:
print('请求成功通过。')
运行结果:
<!DOCTYPE HTML>
<html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
<head>
<meta charset="UTF-8">
<meta name="description" content="提供图书、电影、音乐唱片的
推荐、评论和价格比较,以及城市独特的文化生活。">
.....
window.attachEvent('onload', _ga_init);
}
</script>
</body>
</html>
- 注意:复制header的时候请去掉 这一项'Accept-Encoding':' gzip, deflate, 否则会提示decode的错误。
代理IP
代理IP的使用
为什么要使用代理IP?因为各种反爬机制会检测同一IP爬取网页的频率速度,如果速度过快,就会被认定为机器人封掉你的IP。但是速度过慢又会影响爬取的速度,因此,我们将使用代理IP取代我们自己的IP,这样不断更换新的IP地址就可以达到快速爬取网页而降低被检测为机器人的目的了。
同样利用urllib的request就可以完成代理IP的使用,但是与之前用到的urlopen不同,我们需要自己创建订制化的opener。什么意思呢?
urlopen就好像是opener的通用版本,当我们需要特殊功能(例如代理IP)的时候,urlopen满足不了我们的需求,我们就不得不自己定义并创建特殊的opener了。
request里面正好有处理各种功能的处理器方法,如下:
ProxyHandler, UnknownHandler, HTTPHandler,
HTTPDefaultErrorHandler, HTTPRedirectHandler,
FTPHandler, FileHandler, HTTPErrorProcessor, DataHandler
我们要用的是第一个ProxyHandler来处理代理问题。
让我们看一段代码如何使用。
# coding:utf-8
import urllib.request
import urllib.error
import urllib.parse
# headers信息,从fiddler上或浏览器上可复制下来
headers = {'Accept': 'text/html,application/xhtml+xml,
application/xml;q=0.9,image/webp,image/apng,
*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3;
Win64;
x64) AppleWebKit/537.36 (KHTML,
like Gecko)Chrome/48.0.2564.48
Safari/537.36'
}
# POST请求的信息
value = {'source': 'index_nav',
'form_password': 'your password',
'form_email': 'your username'
}
# 代理IP信息为字典格式,key为'http',value为'代理ip:端口号'
proxy = {'http': '115.193.101.21:61234'}
try:
data = urllib.parse.urlencode(value).encode('utf8')
response = urllib.request.Request(
'https://www.douban.com/', data=data, headers=headers)
# 使用ProxyHandler方法生成处理器对象
proxy_handler = urllib.request.ProxyHandler(proxy)
# 创建代理IP的opener实例
opener = urllib.request.build_opener(proxy_handler)
# 将设置好的post信息和headers的response作为参数
html = opener.open(response)
result = html.read().decode('utf8')
print(result)
except urllib.error.URLError as e:
if hasattr(e, 'reason'):
print('错误原因是' + str(e.reason))
except urllib.error.HTTPError as e:
if hasattr(e, 'code'):
print('错误编码是' + str(e.code))
else:
print('请求成功通过。')
在上面post请求代码的基础上,用自己创建的opener
替换urlopen
即可完成代理IP的操作,代理ip
可以到一些免费的代理IP网站上查找,我整理出几个,如:
运行得到的结果与使用本机IP一样。
超时
设置超时的目的是为了防止爬取网站的时候,等待时间过长而导致效率的降低。有效的超时设置可以强制结束等待而进行下一次的爬取,下面来一段代码看如何使用。
# coding:utf-8
import urllib.request
import urllib.error
import urllib.parse
import socket
# headers信息,从fiddler上或浏览器上可复制下来
headers = {'Accept': 'text/html,application/xhtml+xml,
application/xml;q=0.9,image/webp,image/apng,
*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3;
Win64;
x64) AppleWebKit/537.36
(KHTML, like Gecko)Chrome/48.0
.2564.48 Safari/537.36'
}
# POST请求的信息
value = {'source': 'index_nav',
'form_password': 'your password',
'form_email': 'your username'
}
# 代理IP为字典格式,key为'http',value为'代理ip:端口号'
proxy = {'http': '115.193.101.21:61234'}
# 设置超时为2秒,单位为秒
timeout = 2
try:
# 设置socket超时
socket.setdefaulttimeout(timeout)
data = urllib.parse.urlencode(value).encode('utf8')
response = urllib.request.Request(
'https://www.douban.com/', data=data, headers=headers)
# 使用ProxyHandler方法生成处理器对象
proxy_handler = urllib.request.ProxyHandler(proxy)
# 创建代理IP的opener实例
opener = urllib.request.build_opener(proxy_handler)
# 将设置好的post信息和headers的response作为参数
html = opener.open(response)
result = html.read().decode('utf8')
print(result)
except urllib.error.URLError as e:
if hasattr(e, 'reason'):
print('错误原因是' + str(e.reason))
except urllib.error.HTTPError as e:
if hasattr(e, 'code'):
print('错误编码是' + str(e.code))
except socket.timeout:
print('socket超时')
else:
print('请求成功通过。')
在post和代理IP使用的基础上又增加了超时的使用。
# 设置超时为2秒,单位为秒
timeout = 2
#设置socket超时时间,如果不设置,则会使用默认时间。
socket.setdefaulttimeout(timeout)
# 同时对socket超时timeout的错误设置了异常,timeout错误属于OSerror的子类,时间超出指定timeout就会提示socket超时。
except socket.timeout:
print('socket超时')
urllib库parse解析
除了上面提到的urlencode方法,urllib库的parse中还有很多其它的方法可以使用,如:
#urlparse:把URL解析成6个部分
<scheme>://<netloc>/<path>;<params>?<query>#<fragment>
#urlsplit:把URL解析成5个部分
<scheme>://<netloc>/<path>?<query>#<fragment>
# urlunsplit,urlunparse:进行URL的重组
# 还有urljoin,urldefrag等。
更多用法可以查找官方request源码,也会在后续实战例子中陆续使用介绍。
网友评论