urllib.request的GET和POST方法


urllib.request默认只支持HTTP/HTTPS的GETPOST方法

urllib.parse.urlencode()

urllib 和 urllib2 都是接受URL请求的相关模块,但是提供了不同的功能。两个最显著的不同如下:
  • urllib 仅可以接受URL,不能创建 设置了headers 的Request 类实例;

  • 但是 urllib 提供 urlencode 方法用来GET查询字符串的产生,而 urllib2 则没有。(这是 urllib 和 urllib2 经常一起使用的主要原因)

  • 编码工作使用urllib的urlencode()函数,帮我们将key:value这样的键值对转换成"key=value"这样的字符串,解码工作可以使用urllib的unquote()函数。(注意,不是urllib2.urlencode() )

一般HTTP请求提交数据,需要编码成 URL编码格式,然后做为url的一部分,或者作为参数传到Request对象中。

Get方式

GET请求一般用于我们向服务器获取数据,比如说,我们用百度搜索传智播客https://www.baidu.com/s?wd=传智播客

浏览器的url会跳转成如图所示:

https://www.baidu.com/s?wd=%E4%BC%A0%E6%99%BA%E6%92%AD%E5%AE%A2

在其中我们可以看到在请求部分里,http://www.baidu.com/s? 之后出现一个长长的字符串,其中就包含我们要查询的关键词传智播客,于是我们可以尝试用默认的Get方式来发送请求。

 1 from urllib import request
 2 import urllib.parse
 3 
 4 keyword=input('请输入关键字:')
 5 a=urllib.parse.urlencode({'wd':keyword})   #url编码
 6 # print(a)
 7 # b=urllib.parse.unquote(a)    #url解码
 8 # print(b)
 9 header={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"}
10 fullurl='http://www.baidu.com/s'+'?'+a
11 c=request.Request(fullurl,headers=header)
12 request.urlopen(c)
13 print(fullurl)

 

批量爬取贴吧页面数据

首先我们创建一个python文件, tiebaSpider.py,我们要完成的是,输入一个百度贴吧的地址,比如:

百度贴吧LOL吧第一页:http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=0

第二页: http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=50

第三页: http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=100

发现规律了吧,贴吧中每个页面不同之处,就是url最后的pn的值,其余的都是一样的,我们可以抓住这个规律。

简单写一个小爬虫程序,来爬取百度LOL吧的所有网页。
 1 from urllib import request
 2 import urllib.parse
 3 
 4 #根据url发送请求,获取服务器响应文件
 5 def getPage(url,filename):
 6     print('正在下载'+filename)
 7     header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"}
 8     a=request.Request(url,headers=header)
 9     return request.urlopen(a).read()
10 
11 #将html内容写入到本地
12 def saveFile(filename,html):
13     print('正在保存' + filename)
14     with open(filename,'wb') as f:
15         f.write(html)
16     print('*'*20)
17 
18 #贴吧爬虫调度器,负责组合处理每个页面的url
19 def tiebaSpider(url,startpage,endpage):
20     for page in range(startpage,endpage+1):
21         pn=(page-1)*50
22         fullurl=url+'&pn='+str(pn)
23         print(fullurl)
24         filname=''+str(page) + "页.html"
25         html = getPage(fullurl, filname)
26         saveFile(filname,html)
27     print('谢谢使用!')
28 
29 if __name__ == '__main__':
30     kw=input('请输入要搜索的内容:')
31     startpage=int(input('请输入从第几页开始:'))
32     endpage=int(input('请输入从第几页结束:'))
33 
34     kw=urllib.parse.urlencode({'kw':kw})
35     url='http://tieba.baidu.com/f?'+kw
36 
37     tiebaSpider(url, startpage, endpage)

其实很多网站都是这样的,同类网站下的html页面编号,分别对应网址后的网页序号,只要发现规律就可以批量爬取页面了。


 

POST方式:

上面我们说了Request请求对象的里有data参数,它就是用在POST里的,我们要传送的数据就是这个参数data,data是一个字典,里面要匹配键值对。

有道词典翻译网站:

输入测试数据,再通过使用Fiddler观察,其中有一条是POST请求,而向服务器发送的请求数据并不是在url里,那么我们可以试着模拟这个POST请求。

于是,我们可以尝试用POST方式发送请求。

 1 from urllib import request
 2 import urllib.parse
 3 
 4 # url='http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
 5 url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
 6 header={
 7     # "Accept": "application/json, text/javascript, */*; q=0.01",
 8     "X-Requested-With": "XMLHttpRequest",
 9     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36",
10     "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
11     "Origin": "http://fanyi.youdao.com"
12 }
13 
14 data={
15     "i":"python",
16     "from":"AUTO",
17     "to":"AUTO",
18     "smartresult":    "dict",
19     "client":"fanyideskweb",
20     "salt":    "15825474729954",
21     "sign":"792ead532594975beac7426b8b565dff",
22     "ts":"1582547472995",
23     "bv":"4b1009b506fa4405f21e207abc4459fd",
24     "doctype":    "json",
25     "version":    "2.1",
26     "keyfrom":    "fanyi.web",
27     "action    ":"FY_BY_REALTlME"
28 }
29 
30 datas=urllib.parse.urlencode(data).encode('utf-8')
31 
32 a=request.Request(url,data=datas,headers=header)
33 print(request.urlopen(a).read().decode('utf-8'))
发送POST请求时,需要特别注意headers的一些属性:

Content-Length: 144: 是指发送的表单数据长度为144,也就是字符个数是144个。

X-Requested-With: XMLHttpRequest :表示Ajax异步请求。

Content-Type: application/x-www-form-urlencoded : 表示浏览器提交 Web 表单时使用,表单数据会按照 name1=value1&name2=value2 键值对形式进行编码。

 

获取AJAX加载的内容

有些网页内容使用AJAX加载,只要记得,AJAX一般返回的是JSON,直接对AJAX地址进行post或get,就返回JSON数据了。

"作为一名爬虫工程师,你最需要关注的,是数据的来源"

 1 from urllib import request
 2 import urllib.parse
 3 
 4 
 5 ######post方式
 6 url = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend"
 7 
 8 headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"}
 9 
10 formdata = {
11         "page_limit":"5",
12         "page_start":"20"
13     }
14 
15 data=urllib.parse.urlencode(formdata).encode('utf-8')
16 a=request.Request(url,data=data,headers=headers)
17 
18 print(request.urlopen(a).read().decode('utf-8'))
19 
20 
21 #####get方式
22 url1 = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=5&page_start=20"
23 
24 headers1 = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"}
25 
26 b=request.Request(url1,headers=headers1)
27 # print(request.urlopen(b).read().decode('utf-8'))

问题:为什么有时候POST也能在URL内看到数据?

  • GET方式是直接以链接形式访问,链接中包含了所有的参数,服务器端用Request.QueryString获取变量的值。如果包含了密码的话是一种不安全的选择,不过你可以直观地看到自己提交了什么内容。

  • POST则不会在网址上显示所有的参数,服务器端用Request.Form获取提交的数据,在Form提交的时候。但是HTML代码里如果不指定 method 属性,则默认为GET请求,Form中提交的数据将会附加在url之后,以?分开与url分开。

  • 表单数据可以作为 URL 字段(method="get")或者 HTTP POST (method="post")的方式来发送。比如在下面的HTML代码中,表单数据将因为 (method="get") 而附加到 URL 上:

<form action="form_action.asp" method="get"> <p>First name: <input type="text" name="fname" /></p> <p>Last name: <input type="text" name="lname" /></p> <input type="submit" value="Submit" /> </form> 

处理HTTPS请求 SSL证书验证

现在随处可见 https 开头的网站,urllib2可以为 HTTPS 请求验证SSL证书,就像web浏览器一样,如果网站的SSL证书是经过CA认证的,则能够正常访问,如:https://www.baidu.com/等...

如果SSL证书验证不通过,或者操作系统不信任服务器的安全证书,比如浏览器在访问12306网站如:https://www.12306.cn/mormhweb/的时候,会警告用户证书不受信任。(据说 12306 网站证书是自己做的,没有通过CA认证)

urllib2在访问的时候则会报出SSLError:

import urllib2 url = "https://www.12306.cn/mormhweb/" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} request = urllib2.Request(url, headers = headers) response = urllib2.urlopen(request) print response.read() 

运行结果:

urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>

所以,如果以后遇到这种网站,我们需要单独处理SSL证书,让程序忽略SSL证书验证错误,即可正常访问。

import urllib import urllib2 # 1. 导入Python SSL处理模块 import ssl # 2. 表示忽略未经核实的SSL证书认证 context = ssl._create_unverified_context() url = "https://www.12306.cn/mormhweb/" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} request = urllib2.Request(url, headers = headers) # 3. 在urlopen()方法里 指明添加 context 参数 response = urllib2.urlopen(request, context = context) print response.read() 

关于CA

CA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的受信任的第三方机构,如北京数字认证股份有限公司上海市数字证书认证中心有限公司等...

CA的作用是检查证书持有者身份的合法性,并签发证书,以防证书被伪造或篡改,以及对证书和密钥进行管理。

现实生活中可以用身份证来证明身份, 那么在网络世界里,数字证书就是身份证。和现实生活不同的是,并不是每个上网的用户都有数字证书的,往往只有当一个人需要证明自己的身份的时候才需要用到数字证书。

普通用户一般是不需要,因为网站并不关心是谁访问了网站,现在的网站只关心流量。但是反过来,网站就需要证明自己的身份了。

比如说现在钓鱼网站很多的,比如你想访问的是www.baidu.com,但其实你访问的是www.daibu.com”,所以在提交自己的隐私信息之前需要验证一下网站的身份,要求网站出示数字证书。

一般正常的网站都会主动出示自己的数字证书,来确保客户端和网站服务器之间的通信数据是加密安全的。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM