一、urllib.parse模块

上篇文章学到了data参数,但是data参数进行传递的前要先进行转换格式,这里用到了urllib.parse.urlencode()

(1)urllib.parse.urlencode()  :将字典形式(key-value)的数据转化成查询字符串 

(2)这里还要介绍一个json模块:

JSON(JavaScript Object Notation) :是一种传递对象的语法,对象可以是name/value对,数组和其他对象。 

函数

功能

json.dumps

将 Python 对象编码成 JSON 字符串

json.loads

将已编码的 JSON 字符串解码为 Python 对象

在这次的实例中被用来把网页返回的response的字典转换为python对象。

(3)还要提到一个urllib.request.Request():

urllib.request.Request():传送headers(请求头)等信息。(urlopen()可以发送基本的请求但是这几个参数远远不够)

使用请求头headers的原因:在使用python爬虫爬取数据的时候,经常会遇到一些网站的反爬虫措施,一般就是针对于headers中的User-Agent。如果没有对headers进行设置,User-Agent会声明自己是python脚本,而如果网站有反爬虫的想法的话,必然会拒绝这样的连接。而修改headers可以将自己的爬虫脚本伪装成浏览器的正常访问,来避免这一问题。

 

(4)这里的实例是爬百度翻译。(不要一味看别人的代码,毕竟网站也在不断的变化,掌握方法,学会处理问题)

启示:

1 学会去网页源代码找自己要的数据:一定要知道怎么去找data数据,方法:打开百度翻译的审查元素,打开network查看,HXR里面选择最后一个文件headers最低部就可以找到data字典对应的。然后要去理解其中的含义。

2 关于URL遇到的问题:最开始的时候,我是直接用(http://fanyi.baidu.com)网址,结果返回的不是字典序而是网页代码,于是json.loads那里就开始报错了,一开始没输出来看上网查以为是BOM头的问题,后来才知道是网址的问题。打开的百度翻译的网页要打开的手机版的(http://fanyi.baidu.com/basetrans),打开网页版的(http://fanyi.baidu.com/v2transapi)会返回{“error”:997,”from”:”en”,……}。

代码:

import urllib.request
import urllib.parse
import json
import codecs
content = input("请输入要翻译的内容:")
data = {}
#打开network查看,HXR里面选择最后一个文件headers最低部就可以找到data
data['from'] = 'en'#英文
data['to'] = 'zh'#中文
#英译中,这里是可以选择的
data['query'] = content
data['transtype'] = 'enter'
data['sipel_means_flag'] = '3'
data = urllib.parse.urlencode(data).encode("utf-8")
#data应该是bytes,所以上传给server时需要转换成ascii数据。
head ={}
head['User-Agent'] = 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Mobile Safari/537.36'
url = "http://fanyi.baidu.com/basetrans"
rep = urllib.request.Request(url,data,head)
response = urllib.request.urlopen(rep)
html = response.read()
'''
原先用http://fanyi.baidu.com/v2transapi一直报错以为是BOM头的问题
所以写了:(除去BOM头)
if html[:3] == codecs.BOM_UTF8:
    html = html[3:]
结果是打开这个网页一看就是个报错的网址,返回的是{“error”:997,”from”:”en”,……}
上网查了一下说是:打开界面发现headers中sign是动态生成的所以考虑用手机版网页
也就是上面提到的http://fanyi.baidu.com/basetrans
'''
html = html.decode("utf-8")
translat_result = json.loads(html)
#返回的信息是字典可以用内置模块json,将已编码的 JSON 字符串解码为 Python 对象
rst = translat_result["trans"][0]["dst"]
print("翻译的结果是:%s"%rst)

(5)补充一个知识点,如何隐藏身份不被反爬虫,使用代理IP:

为什么要使用代理IP:User-Agent已经设置好了,但是代码访问的速度是很快的,如果用代码一直访问一个网站,一个固定IP访问的频率就会很高,而人的访问速度是没有那么快的,而且高频率的访问会给服务器带来压力。所以有一些网站会设置一个IP访问频率的阈值,来判断是不是人访问。

解决的办法,就是一种是设置延时还有一种就是代理IP。网络中的身份之一就是IP,访问太多次就会被网站拒之门外,这时候就可以用代理IP(相当于换个ip)继续去访问。

在写代码前,先去一些代理IP的网站(例如 西刺代理 全国代理ip)选好一个IP地址。

我选了:116.225.110.126:8888

这里要用到的重要代码介绍:

opener:

为什么使用opener:之前一直使用的是urlopen(url)这种形式来打开网页,它是一个特殊的opener(也就是模块帮我们建好的),传入的参数仅仅是url,data,timeout。但是基本的urlopen()方法不支持debug模式和代理、cookie等其他的HTTP/HTTPS高级功能。如果要实现这些请求的话,我们需要自己定义Handler和opener。

讲到opener还要补充介绍一下handlers:

handlers:Openers使用处理器handlers,所有的“繁重”工作由handlers处理。每个handlers知道如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面。

如何使用opener:可以使用相关的 Handler处理器urllib.request.ProxyHandler()来创建特定功能的处理器对象;

urllib.request.ProxyHandler(proxies):设置代理服务器。proxies为字典)

然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象;

urllib.request.build_opener():用来创建opener对象)

使用自定义的opener对象,调用open()方法发送请求。

opener.open():发送请求使用自定义的代理,但urlopen()则不使用自定义代理。)

或者用 urllib.install_opener()方法处理opener,然后还是用urlopen()发送请求。

urllib.install_opener():将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理。)

实例代理ip访问百度:

import urllib.request

url = 'https://www.baidu.com'
proxy = {'http':'116.225.110.126:'}
proxy_support = urllib.request.ProxyHandler(proxy)
opener = urllib.request.build_opener(proxy_support)
opener.addheaders = [('User-Agent','Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Mobile Safari/537.36')]
req = urllib.request.Request(url)
response = opener.open(req)
html = response.read().decode("utf-8")
print(html)

如果返回的是由于目标机器积极拒绝就说明ip可能是无效的。