Python爬虫教程

第一章: 初学乍练-Python快速入门

第二章: 初窥门径-从全局把握网络爬虫

第三章: 爬虫数据-网页与JSON

第四章: 爬虫核心-HTTP协议

第五章: 手到擒来-数据的抓包

第六章: 利刃出鞘-HTTP请求库

第七章: 尘埃落定-数据的解析

第八章: 逆向初探-JS逆向

第九章: 爬虫进阶-Selenium, 中间人拦截

第十章:斗转星移-常用的反爬策略及应对方法

首页 > Python爬虫教程 > 第六章: 利刃出鞘-HTTP请求库 > 6.2节: URL的读取与解析-urllib

6.2节: URL的读取与解析-urllib

薯条老师 2021-03-05 09:13:05 236435 0

编辑 收藏

广州番禺Python爬虫小班周末班培训

第四期线下Python爬虫小班周末班已经开课了,授课详情请点击:http://chipscoco.com/?id=232

6.2.1 urllib的四大组件

urllib是Python中的一个内置package,其由以下四大模块组成:

模块名

描述

urllib.request

打开和读取url

urllib.parse

解析url

urllib.robotparser

解析robots.txt文件

urllib.error

包含urilib.request模块抛出的异常

使用urllib中的某一个模块,直接在脚本中导入即可,例如导入urllib.request:

# 导入request模块
import urllib.request

在本节教程中,主要讲解编写爬虫程序常用的request,parse以及error模块。

6.2.2 url读取:urllib.request

urllib.request模块基于HTTP/1.1,在向服务端发起请求时,会在请求头中包含Connection:close的请求字段。

在HTTP/1.1协议中,客户端与服务端默认使用长连接,客户端如需保持短连接方式(请求处理完毕后立即关闭连接),需要在请求中指定Connection字段值为close。

现对request模块中的常用操作进行讲解:

(1) urllib.request.urlopen

该函数用来打开url:

urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, context=None)

参数名

描述

url

http url,可为字符串或request对象(urllib.request.Request)

data

发送额外的数据给http服务器,须为bytes类型,默认为None。

timeout

可选的请求超时参数,没有传递时会使用一个默认的超时时间,仅用于http,https,ftp连接

context

  ssl.SSLContext实例,用来定义SSL的传输选项,默认为None

cafile,capath

  cafile指向一个PEM格式的CA证书文件,capath则指向一个包含一系列PEM格式的CA证书文件的目录

urlopen代码实例-抓取Python官网首页:

# 导入request模块
import urllib.request
# python官网的url
url =  'http://python.org/'
with urllib.request.urlopen(url) as response:
    # urlopen方法返回的是一个字节流对象,需通过decode方法转换为字符串
    html = response.read().decode('utf-8')

调用urlopen方法时,默认发起的是GET请求,如需提交数据给服务端,需通过data参数进行传递,此时发起的是POST请求。通过Python中的字典类型,可快速地构建提交的数据,然后再调用urllib.parse的urlencode方法,将其转换为字符串。

代码实例-提交数据给服务端:

import urllib.parse
# 以下url并不存在,读者可使用tornado快速搭建一个本地服务器来进行测试
url = ‘http://localhost:8090/login’
values = {'name' : 'chipscoco', 'password': 'forget'}
data = urllib.parse.urlencode(values)

# 必须传递字节流类型
data = data.encode('utf-8')

with urllib.request.urlopen(url, data=data) as response:
   the_response = response.read().decode('utf-8')

使用Request类可以对http请求进行更细粒度的控制,比如请求头,请求方法。

urllib.request.Request(url,data=None,headers={},origin_req_host=None, unverifiable=False, method=None)

参数名

描述

url

有效的url字符串

data

发送额外的数据给http服务器,须为bytes类型,默认为None。

headers

字典类型,用来定义HTTP请求头

origin_req_host

  定义源服务器的主机名或ip地址

unverifiable

  用来指定用户的请求是否无法验证,默认为False

method

  用来指定HTTP的请求方法,字符串类型,例如:HEAD,GET,POST

urllib.request.Request对象常用方法:

方法名

描述

get_method

返回Request对象的http请求方法

add_header

添加http请求头

has_header

判断Request对象是否包含某请求头

代码实例-为爬虫程序设置UA:

import urllib.request
# 以下url并不存在,读者可将其替换为真实的网页url
url = 'http://www.justtest.com'
# Chrome浏览器的UA
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57'
 
# 设置爬虫程序的UA,可在一定程度上防止被服务端反爬
headers = {'User-Agent': user_agent}
 
req = urllib.request.Request(url=url, headers=headers)
with urllib.request.urlopen(req) as response:
   the_page = response.read()

(2) urllib.request.build_opener

该函数用来构建一个OpenerDirector对象:build_opener([handler, ...])

OpenerDirector对象会链式地按序处理在build_opener方法中传递的处理器,处理器需为BaseHandler,或其子类。OpenerDirector对象常用方法:

方法名

描述

add_handler(self,handler)

添加URL处理器

open(self, fullurl, data=None)

打开完整的url

Python所提供的常用url处理器:

处理器

描述

HTTPRedirectHandler

  用于发起重定向请求

HTTPCookieProcessor

用于处理HTTP Cookies

ProxyHandler

用于发起代理请求

HTTPPasswordMgr

保存用户的账号和密码,以发起需授权验证的请求

HTTPBasicAuthHandler

用于web客户端授权验证

HTTPSHandler

用于发起https请求

在第四章中讲到了cookie, 通过cookie可以保存用户登录的状态信息。在本小节代码实例中,通过http.cookiejar来保存登录成功后的cookie信息,通过HTTPCookieProcessor来处理HTTP Cookie请求。

代码实例-模拟登录chipscoco:

import urllib.request
import urllib.parse
import http.cookiejar

# 以下为薯条老师博客的登录url
login_url = 'http://chipscoco.com/zb_users/plugin/YtUser/cmd.php?act=verify'# Chrome浏览器的UA
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57'
headers = {'User-Agent': user_agent}
 
# 构造一个form data, username为登录的用户名,edtPassWord为加密后的登录密码
form_data = {"username":"test", "edtPassWord":"47ec2dd791e31e2ef2076caf64ed9b3d"}

# 对字典对象进行url编码,由于Request中的data需传递bytes类型,故还需执行encode方法
login_form_data = urllib.parse.urlencode(form_data).encode("utf-8")
req = urllib.request.Request(url=login_url, headers=headers, data=login_form_data)
# 构造一个cookiejar对象来保存cookie信息
cookiejar = http.cookiejar.CookieJar()
cookie_processor = urllib.request.HTTPCookieProcessor(cookiejar)
opener = urllib.request.build_opener(cookie_processor)
opener.open(req)
for item in cookiejar:
    print(item.name + '=' + item.value)

www.chipscoco.com为薯条老师的个人博客(使用z-blog搭建的简单博客),为方便同学们进行模拟登录才开放的测试账号。在实际的模拟登录中,需要同学们找出网站的登录接口,及其请求参数,分析接口的请求过程,对参数的加密方式等,这样才可以实现自动登录。关于如何分析网站的登录接口,如何对接口进行数据抓包等,可复习第五章中的内容。

6.2.3 url解析:urllib.parse

(1) urllib.parse.urlparse

使用urlparse函数可以方便地解析出url中的协议类型,主机名,端口号,请求路径等信息:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)

参数名

描述

urlstring

待解析的url字符串

scheme

指定解析的url地址的scheme,仅当url中没有scheme时才需传递

allow_fragments

默认为True, 会解析url中的分片标识。为False时,url中的分片标识不会被解析。

函数返回一个包含6个元素的命名元组,各元素可通过索引或属性名进行访问。命名元组的属性名如下表所示:

属性名

描述

scheme

url地址的scheme

netloc

url的网络位置,比如常见的域名:端口号

path

url中的请求路径

params

url中请求路径后的参数

query

url中的查询参数

fragment

url中的锚定位,即HTML中的分片标识

代码实例-解析HTTP URL:

>>> from urllib.parse import urlparse

>>> url = urlparse('http://www.test.com:8090/index.html?language=Python&language=C++')

>>> url

ParseResult(scheme='http', netloc='www.test.com:8090', path='/index.html', params='', query='language=Python&language=C++', fragment='')

>>> url.netloc

'www.test.com:8090'

>>> url.path

'/index.html'

>>> url.query

'language=Python&language=C++'

通过命名元组的query属性可以返回查询参数,如需对查询参数进一步解析,可以使用urllib.parse.parse_qs方法:

>>> import urllib

>>> urllib.parse.parse_qs(url.query)

{'language': ['Python', 'C  ']}

以上代码均在Python交互模式中进行测试。

(2) urllib.parse.urlencode

urlencode函数用来将映射类型或二维的元组类型转换为通过'&'分隔的url编码:

urllib.parse.urlencode(query, doseq=False, safe='',encoding=None,errors=None,quote_via=quote_plus)

属性名

描述

query

表示映射类型(例如字典)或二维的元组对象

doseq

默认为False,为True时表示二维元组中的每一个元素(元组)中的第二个元素为一个序列,例如(('language',('c++','python')))

safe

传递给quote_via所指定的url编码函数,用来指定某字符不需要编码

encoding

传递给quote_via所指定的url编码函数,用来指定字符编码

errors

传递给quote_via所指定的url编码函数,用来指定发生编码错误时该如何处理

quote_via

默认为quote_plus函数,用来生成url编码,quote_plus函数会将空白字符编码为+号,将/编码为%2F

关于urlencode的使用,可以查看5.1.2节中的代码实例:模拟登录chipscoco。如需将字符串类型进行url编码及解码,可以使用urllib.parse.quote,urllib.parse.unquote函数,前者用来生成字符串的url编码,后者用来将url编码解码为字符串。关于函数的具体用法,可查找官方文档,或直接在Python交互模式中使用help来查找。

6.2.4 url异常:urllib.error

urllib.error 模块为urllib.request所引发的异常定义了如下异常类:

异常类

描述

URLError

urllib.error中的异常类的基类,属性reason描述了异常原因

HTTPError

code属性表示HTTP状态码,reason属性表示引起异常的原因

ContentTooShortError

此异常会在 urlretrieve()函数检测到已下载的数据量小于期待的数据量(由 Content-Length请求头指定的长度)时被引发

代码实例-捕获url异常:

import urllib.parse
from urllib.error import HTTPError
# 以下url并不存在,读者可使用tornado快速搭建一个本地服务器来进行测试
url = ‘http://localhost:8090/login’
values = {'name' : 'chipscoco', 'password': 'forget'}

data = urllib.parse.urlencode(values)
# 必须传递字节流类型
data = data.encode('utf-8')
try:
    response =  urllib.request.urlopen(url, data=data)
except HTTPError as e:
    print(e.code, e.reason)

6.2.5 知识要点

(1) urllib是Python中的一个内置package,用来处理url的读取及解析。其由以下四大模块组成 :urllib.request,urllib.parse,urllib.robotparser,urllib.error。

(2) 在HTTP/1.1协议中,客户端与服务端默认使用长连接,客户端如需保持短连接方式(请求处理完毕后立即关闭连接),需要在请求中指定Connection字段值为close。

6.2.6 课后习题

(1) Python后端工程师高薪就业班,月薪10K-15K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,免费领取课程大纲
(3) Java后端开发工程师高薪就业班,月薪10K-20K, 免费领取课程大纲
(4) Python大数据工程师就业班,月薪12K-25K,免费领取课程大纲

扫码免费领取学习资料:



欢迎 发表评论: