在Python中有很多库可以用来模拟浏览器发送请求抓取网页,本文中介绍使用urllib2来实现获取网页数据。
urllib2是在Python2标准库中的,无需安装即可使用,在Python3中不能使用urllib2,在Python3中urllib2被改为了urllib.request,所以本文中的代码在Python3中运行时,把urllib2替换成urllib.request,得到的结果是一样的。
一、使用urllib2获取数据
# coding=utf-8
import urllib2
response = urllib2.urlopen("http://www.baidu.com")
print(response.read())
运行上面的代码,会获取到百度首页的html文件。我们直接在浏览器中打开百度首页,右键后点击“查看网页源代码”,得到的结果是一模一样的,说明我们已经通过urllib2获取到了百度首页的数据。
二、urllib2添加报头参数
在上面的例子中,urlopen()的参数只有一个url。但是很多情况下,我们需要执行更复杂的操作,比如增加HTTP报头,这时,通过创建一个 Request 实例来作为urlopen()的参数,访问的url地址作为 Request 实例的参数,并将增加的HTTP报头等内容也传递到 Request 实例中。
# coding=utf-8
import urllib2
url = "https://www.taobao.com/"
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
"Referer": "https://www.hao123.com/",
"Upgrade-Insecure-Requests": 1,
}
request = urllib2.Request(url, headers=headers)
request.add_header("Connection", "keep-alive") # 通过add_header也可以添加headers内容
response = urllib2.urlopen(request)
print(response.code)
print(response.read())
在上面的代码中,我们使用了两种方式添加请求报头,包含user-agent, Referer, Upgrade-Insecure-Requests, Connection, 如果还需要添加其他的内容,按照相同方法添加即可。
其中的user-agent用于说明请求者的身份,是用什么浏览器发的请求,如果没有user-agent则表示不是用浏览器访问的。Referer用于说明访问者从哪个地方点击链接进入访问的网页,如果没有,则说明不是通过浏览器访问,常称为“盗链”。
运行结果与我们在淘宝网首页,右键后点击“查看网页源代码”看到的结果相同。
三、使用urllib来给url添加查询字符串
在我们使用urllib2获取网页的数据时,肯定不是只获取首页数据,我们还需要获取一些其他页面。
这时候需要在url中拼接查询字符串,Python的urllib库提供了urlencode方法来将字典转换成查询字符串,而urllib2没有urlencode,所以可以通过urllib生成查询字符串来给urllib2使用。
# coding=utf-8
import urllib
import urllib2
url = "https://www.baidu.com/s?"
key_dict = {"wd": "python"}
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",}
query_str = urllib.urlencode(key_dict)
url = url + query_str
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
print(response.read())
上面的代码通过urllib的urlencode方法生成了查询字符串,拼接到url中,这样就可以实现请求的url中有查询字符串了。
获取到的页面与我们在百度首页搜索python的页面相同。
四、使用urllib2发送POST请求
上面的例子中,我们使用的都是GET方法,接下来我们使用POST方法。POST方法的响应是根据我们在请求体中携带的数据来返回的,通过data参数可以给请求对象设置请求体。
另一方面,之前我们获取到的结果是一个html文件,这是一个网页页面,对于我们来说并不是特别友好,所以我们需要从html文件中解析出我们需要的那部分数据。在获取到响应结果后,可以通过json模块来解析出我们想要的数据。
# coding=utf-8
import urllib2
import urllib
import time
import json
url = "https://fanyi.qq.com/api/translate"
headers = {
"Origin": "https://fanyi.qq.com",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
# "Referer": "https://fanyi.qq.com",
# "Host": "fanyi.qq.com",
# "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
# "Accept": "application/json, text/javascript, */*; q=0.01"
}
time_str = str(int(1000 * time.time()))
key_dict = {
"source": "zh",
"target": "en",
"sourceText": "发送 POST 请求",
"sessionUuid ": "translate_uuid" + time_str
}
data = urllib.urlencode(key_dict)
request = urllib2.Request(url, data=data, headers=headers)
response = urllib2.urlopen(request)
print(response.code)
html = response.read()
result = json.loads(html)
print(result['translate']['records'][0]['targetText'])
运行结果:
200
Send POST request
上面是以腾讯翻译来作为例子,通过data参数上传请求报文,最后从响应中解析出来翻译结果。
使用urllib2发送请求时,我们并不需要声明使用的是GET请求还是POST请求,当我们给Request对象传入了data参数,urllib2就会自动以POST方式发送请求。
在我们进行POST请求时,不同网站可能会对报文进行核验(并且还可能经常变化),核验通过了才能请求成功,如上面请求头中的Origin参数如果没有,就报错500。所以使用时要灵活应对。
正常工作中,如果我们获取自己公司项目的接口数据,一般都是有接口文档的,但是在获取一些公共的网站时,往往不是那么容易。关于通过POST请求腾讯翻译,谷歌翻译,有道翻译,百度翻译等的方法,可以找一些翻译接口破解的文章进行学习。