Python爬虫urllib2库的基本使用系列(三)

1.  网页抓取

所谓网页抓取,就是把URL地址中指定的网络资源从网络流中抓取出来。在Python中有很多库可以用来抓取网页。

在python2中自带urllib和urllib2。两个最显著的不同如下:

<1> urllib 模块仅可以接受URL,不能创建 设置headers 的Request 类实例;

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

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

在python3中urllib2被改为urllib库下request模块。编码使用urllib库下parse模块

from urllib import parse

# url转码操作,只有转码后浏览器才会识别该url

kw = {'name': '中国'}

res = parse.urlencode(kw)

print(res)

res2 = parse.unquote(res)

print(res2)

# 结果如下:

# name=E5%B0%8F%E5%8F%AF

# name=中国

注意:本文采用python3.5的python爬虫环境。

2. urlopen发送请求,返回响应案例

# 导入urllib 库下request模块

from urllib import request

# 向指定的url发送请求,并返回服务器响应的类文件对象

response = request.urlopen("http://www.baidu.com")

# 类文件对象支持 文件对象的操作方法,如read()方法读取文件全部内容,返回字符串

html = response.read()

# 打印字符串

print(html)

3. Request构造请求对象

# 导入urllib 库下request模块

from urllib import request

# url 作为Request()方法的参数,构造并返回一个Request对象

req = request.Request("http://www.baidu.com")

# Request对象作为urlopen()方法的参数,发送给服务器并接收响应

response = request.urlopen(req)

html = response.read()

print(html)

注意:

新建Request实例,除了必须要有 url 参数之外,还可以设置另外两个参数:

<1> data(默认空):提交的Form表单数据,同时 HTTP 请求方法将从默认的 "GET"方式 改为 "POST"方式。

<2> headers(默认空):参数为字典类型,包含了需要发送的HTTP报头的键值对。

4.  User-Agent伪装成浏览器进行请求

浏览器 就是互联网世界上公认被允许的身份,如果我们希望我们的爬虫程序更像一个真实用户,那我们第一步就是需要伪装成一个被浏览器。用不同的浏览器在发送请求的时候,会有不同的 User-Agent 报头。

python2中的urllib2默认的User-Agent头为:Python-urllib/x.y (x和y 是Python 主.次 版本号,例如 Python-urllib/2.7)

from urllib import request

def loadPage():

# 包含一个请求报头的headers, 发送的请求会附带浏览器身份发送

headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}

# 构造一个请求对象

req = request.Request("http://www.baidu.com/", headers=headers)

# 发送http请求,返回服务器的响应内容

# response响应是一个类文件对象

response = request.urlopen(req)

# 类文件对象支持文件操作的相关方法,比如read():读取文件所有内容,返回字符串

return response.read()

if __name__ == "__main__":

# print __name__

html = loadPage()

# 打印字符串,也就是整个网页的源码

print(html)

5. 添加更多的Header信息

在 HTTP Request 中加入特定的 Header,来构造一个完整的HTTP请求消息。

可以通过调用Request.add_header() 添加/修改一个特定的header 也可以通过调用Request.get_header()来查看已有的header。

# 导入urllib 库下request模块

from urllib import request

url = "http://www.baidu.com"

# IE 9.0 的 User-Agent

user_agent = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"}

req = request.Request(url, headers=user_agent)

# 也可以通过调用Reques.add_header() 添加/修改一个特定的header为长链接

req.add_header("Connection", "keep-alive")

# 也可以通过调用Request.get_header()来查看header信息

# req.get_header(header_name="Connection")

response = request.urlopen(req)

print(response.code)  # 可以查看响应状态码

# 网页源代码

html = response.read()

print(html)

6. 随机添加/修改User-Agent

from  urllib import request

import random

def loadPage(url):

# User-Agent 列表

useragent_list = [

"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",

"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",

"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",

"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",

"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",

"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",

"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",

"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",

"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",

]

# 随机选择一个User-Agent字符串

# random.choice()这个方法可以从列表中随机的取出一个元素

user_agent = random.choice(useragent_list)

# 构造请求对象

req = request.Request(url)

# 添加一个请求报头,添加的时候是User-Agent

req.add_header("User-Agent", user_agent)

# 查看指定请求报头,获取的时候一定是User-agent

print(req.get_header("User-agent"))

# 发送请求,返回服务器响应

reseponse = request.urlopen(req)

# 返回响应的html内容

return reseponse.read()

if __name__ == "__main__":

url = input("请输入需要抓取的网页:")

html = loadPage(url)

print(html)

7. GET方式请求,爬取贴吧案例

# 处理HTTP请求,在python2中是urllib2,在python3中是urllib.request

from urllib import request, parse

def loadPage(url, filename):

'''

作用:根据url发送请求,获取服务器响应文件

url:需要爬取的url地址

filename: 文件名

'''

print("[LOG]: 正在下载" + filename)

headers = {

"User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6"}

# 构造请求对象

req = request.Request(url, headers=headers)

# 发送请求,返回响应结果

response = request.urlopen(req)

if response.getcode() == 200:

return response.read()

else:

print("[ERR]: 下载失败...")

def writePage(html, filename):

"""

作用:保存服务器响应文件到本地磁盘文件里

html: 服务器响应文件

filename: 本地磁盘文件名

"""

print("[LOG]: 正在写入" + filename)

with open(filename, "wb") as f:

f.write(html)

def tiebaSpider(url, beginPage, endPage):

"""

作用:负责处理url,分配每个url去发送请求

url:需要处理的第一个url

beginPage: 爬虫执行的起始页面

endPage: 爬虫执行的截止页面

"""

for page in range(beginPage, endPage + 1):

pn = (page - 1) * 50

# 对pn进行转码后,才能在浏览器中识别

keyword = parse.urlencode({"pn": pn})

fullurl = url + "&" + keyword

print(fullurl)

# 爬取到的数据存放的文件名称

filename = "第" + str(page) + "页.html"

html = loadPage(fullurl, filename)

writePage(html, filename)

if __name__ == "__main__":

tiebaName = input("请输入需要爬取的贴吧名:")

beginPage = int(input("请输入爬取的起始页:"))

endPage = int(input("请输入爬取的终止页: "))

# "https://tieba.baidu.com/f? kw=%E6%9D%8E%E6%AF%85&pn=50"

baseURL = "http://tieba.baidu.com/f?"

keyword = {"kw": tiebaName}

kw = parse.urlencode(keyword)

url = baseURL + kw

tiebaSpider(url, beginPage, endPage)

8. POST方式爬取有道词典案例

from urllib import request, parse

def loadPage():

# 新版本的有道翻译的接口

# url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=null"

# 老版本的有道翻译的接口

url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&sessionFrom=null"

# i = bytes(input("请输入需要翻译的句子:").encode('utf-8'))

i = input("请输入需要翻译的句子:")

# form表单数据,通过网页源代码可查看携带的请求参数

formdata = {

"i": i,

"from": "AUTO",

"to": "AUTO",

"smartresult": "dict",

"client": "fanyideskweb",

# "salt" : "1500253430162",

# "sign" : "db86dafb01c61b4c5bc85bc0868ff7f6",

"doctype": "json",

"version": "2.1",

"keyfrom": "fanyi.web",

"action": "FY_BY_CL1CKBUTTON",

"typoResult": "true",

}

# 将数据转为url编码,注意这个地方要加encode()编码方式,否则会报错如下:

# "POST data should be bytes or an iterable of bytes. It cannot be of type str.

data = parse.urlencode(formdata).encode(encoding='utf8')

# 请求报头

headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}

# 构造一个请求,因为有data参数,所有请求会从默认的get变成post

# 发送post请求同时,会把data数据传输到指定的url地址

req = request.Request(url, data=data, headers=headers)

# 发送请求,返回响应

response = request.urlopen(req)

# 去除字符串首尾的空格

content = response.read().strip()

# print content

# 将字符串格式的字典,转换为真正的字典

content = eval(content)

print(content)

# 取出字典的值

print(content["translateResult"][0][0]["tgt"])

if __name__ == "__main__":

loadPage()

# 结果如下:

# 请输入需要翻译的句子:hello

# 返回的json字符串如下:

# {'type': 'EN2ZH_CN',

#  'translateResult': [[{'src': 'hello', 'tgt': '你好'}]],

#  'smartResult': {'type': 1, 'entries': ['', 'n. 表示问候, 惊奇或唤起注意时的用语', 'int. 喂;哈罗', 'n. (Hello)人名;(法)埃洛']},

#  'errorCode': 0,

#  'elapsedTime': 1 }

# 最终结果:

# 你好

9. 处理HTTPS请求 SSL证书验证

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

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

如果没有ssl证书认证,会报如下错误:

urllib.error.URLError:

from urllib import request

import ssl

# 表示忽略网站的不合法证书认证

context = ssl._create_unverified_context()

headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)"}

req = request.Request("https://www.12306.cn/mormhweb/", headers=headers)

# 在urlopen()添加context参数,请求将忽略网站的证书认证

response = request.urlopen(req, context=context)

print(response.read())

关于CA数据证书认证

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

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

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

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

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

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

你可能感兴趣的:(Python爬虫urllib2库的基本使用系列(三))