爬虫网络库(3.urllib网络库)

urllib基础知识

urllib四个模块
  1、request: 最基本的HTTP请求模块,可以用来发送HTTP请求,并接收服务端的相应数据。就像输入网址敲回车
  2、error: 异常处理模块,如果出现请求错误可以捕捉异常,然后根据实际情况,重试或者忽略
  3、parse: 工具模块,提供了很多处理URL的API,如拆分、解析、合并等
  4、robotparser: 只要用来识别网站的robots文件,然后判断哪些网站可以抓取,那些网站不能抓取

Request类构造方法参数的作用:
  1、url:用于发送请求的URL,必需
  2、data:要提交的数据,必须是bytes类型
  3、headers:请求头,字典类型
  4、origin_req_host:请求方的host名称或IP地址
  5、unverifiable:表示这个请求是否是无法验证的,默认是False,用户没有足够的权限来选择接收这个请求的结果
  6、method:用来指定请求的方法,GET、POST、PUt等

3.1 HTTP Response示例

import urllib.request
# 想京东商城发送HTTP GET请求,urlopen函数既可以使用http,也可以使用https
response = urllib.request.urlopen('https://www.jd.com')
# 输出urlopen函数返回值的数据类型
print('response的类型:',type(response))
# 输出响应状态码、响应消息和HTTP版本
print('status:',response.status,'msg:',response.msg,'version:',response.version)
# 输出所有的响应头信息
print('headers:',response.getheaders())
# 输出名为Content-Type的响应头信息
print('headers.Content-Type',response.getheader('Content-Type'))
# 输出京东商城首页所有的HTML代码(经过utf-8解码)
print(response.read().decode('utf-8'))

3.2 HTTP POST示例

import urllib.request
# 将表单数据转换为bytes类型,用utf-8编码
data=bytes(urllib.parse.urlencode({'name':'Bill','age':30}),encoding='utf-8')
#提交HTTP POST请求
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
# 输出响应数据
print(response.read().decode('utf-8'))

3.3 Timeout超时设置

import urllib.request
import socket
import urllib.error
try:
    # 将请求设置为 0.1s
    response=urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
except urllib.error.URLError as e:
    # 判断抛出的异常是否为超时异常
    if isinstance(e.reason,socket.timeout):
        # 进行异常处理,只是简单输出了“超时”,真实情况可以进行更复杂的处理
        print('超时')
# 在这里继续进行爬虫工作
print('在这里继续进行爬虫工作')

3.4 Host请求头设置示例

from urllib import request,parse
# 定义要提交的HTTP请求的URL
url = 'http://httpbin.org/post'
# 定义HTTP请求头,其中who是自定义的请求字段
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3 '
                 'AppleWebKit/537.36(KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
    'Host':'httpbin.org',
    'who':'Python Scrapy'
}
# 定义表单数据
dict = {
    'name':'Bill',
    'age':30
}
# 将表单数据转换为bytes形式
data = bytes(parse.urlencode(dict),encoding='utf-8')
#定义Request对象,通过Request类的构造方法指定了表单数据和HTTP请求头
req = request.Request(url=url,data=data,headers=headers)
#urlopen函数通过Request对象向服务端发送HTTP POST请求
response=request.urlopen(req)
#返回输出结果
print(response.read().decode('utf-8'))

3.5 设置中文的HTTP请求头并获取

from urllib import request
from urllib.parse import unquote,urlencode
import base64
url = 'http://httpbin.org/post'
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3 '
                 'AppleWebKit/537.36(KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
    'Host':'httpbin.org',
    #设置中文HTTP请求头,用url编码格式
    'Chinese1':urlencode({'name':'李宁'}),
    #设置中文HTTP请求头,用base64编码格式
    'MyChinese':base64.b64encode(bytes('这是中文HTTP请求头',encoding='utf-8')),
    'who':'Python Scrapy'
}
dict = {
    'name':'Bill',
    'age':30
}
data = bytes(urlencode(dict),encoding='utf-8')
req = request.Request(url=url,data=data,headers=headers,method="POST")
# 通过add_header方法添加中文HTTP请求头,url编码
req.add_header('Chinese2',urlencode({"国籍":"中国"}))
response=request.urlopen(req)
# 获取服务端的响应消息
value = response.read().decode('utf-8')
print(value)
import json
# 将返回值转换为json对象
responseObj = json.loads(value)
# 解码url编码格式的HTTP请求头
print(unquote(responseObj['headers']['Chinese1']))
# 解码url编码格式的HTTP请求头
print(unquote(responseObj['headers']['Chinese2']))
# 解码base64编码格式的HTTP请求头
print(str(base64.b64decode(responseObj['headers']['Mychinese']),'utf-8'))

3.7 ProxyHandle设置代理

通过ProxyHandler设置HTTP和HTTPS代理,然后访问相关的页面,并输出服务器的响应结果

from urllib.error import URLError
from urllib.request import ProxyHandler,build_opener

# 创建ProxyHandler对象,并指定HTTP和HTTPS代理的IP和端口号
proxy_handler = ProxyHandler({
    'http':'http://182.86.191.16:24695',
    'https':'https://182.86.191.16:24695'
})
opener =build_opener(proxy_handler)
try:
    response = opener.open('https://www.jd.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

3.8 获取并读取Cookie的示例

ps = '''首先运行此flask框架的内容在执行第二个文件的获取Cookie的操作'''
from flask import Flask
from flask import request
app = Flask(__name__)
# 输出客户端发送过来的所有Cookie,以及名为MyCookie的Cookie的值
@app.route("/readCookie")
def readCookie():
    print(request.cookies)
    print(request.cookies.get('MyCookie'))
    return "hellow world"
# 向客户端写入名为id的Cookie(设置Set-Cookie字段)
@app.route('/writeCookie')
def writeCookie():
    response = app.make_response('write cookie')
    # 写入Cookie
    response.set_cookie("id",value="123456789")
    response.set_cookie("user", value="xiao_zang")
    return response
if __name__ == '__main__':
    app.run()
ps = '''再运行次文件获取Cookie'''
import  http.cookiejar,urllib.request
# 创建CookieJar对象
cookie = http.cookiejar.CookieJar()
# 创建HTTPCookieProcessor对象
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
# 给http://www.baidu,com发送请求,获得相应数据
response = opener.open('http://www.baidu.com')
print('-----http://www.baidu.com-----')
# 输出服务端发送的所有Cookie
for item in cookie:
    print(item.name + '=' + item.value)
print('-----http://127.0.0.1:5000/writeCooke-----')
# 下面的代码用同样的方式访问CookieServer,并输出返回的Cookie
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://127.0.0.1:5000/writeCookie')
for item in cookie:
    print(item.name + '=' + item.value)

运行结果: -----http://www.baidu.com----- BAIDUID=D9805637EF14D31784DE7D2674560997:FG=1 BIDUPSID=D9805637EF14D3170E50C201F143C0C2 H_PS_PSSID=35837_31253_35978_36088_36165_34584_36144_36120_36073_35993_35956_35316_26350_35868_36102_36061 PSTM=1648304135 BDSVRTM=0 BD_HOME=1 -----http://127.0.0.1:5000/writeCooke----- id=123456789 user=xiao_zang

3.9 CookieFile

可以使用MozillaCookieJar类和LWPCookieJar类在获得Cookie的同时
将Cookie分别保存成Mozilla浏览器格式和libwww-perl(LWP)格式

ps = ''''''
import http.cookiejar,urllib.request
filename1 = 'cookies1.txt'
filename2 = 'cookies2.txt'
# 创建MozillCookieJar对象
cookie1 = http.cookiejar.MozillaCookieJar(filename1)
# 创建LWPCookieJar对象
cookie2 = http.cookiejar.LWPCookieJar(filename2)
handler1 = urllib.request.HTTPCookieProcessor(cookie1)
handler2 = urllib.request.HTTPCookieProcessor(cookie2)
opener1 = urllib.request.build_opener(handler1)
opener2 = urllib.request.build_opener(handler2)
opener1.open('http://www.baidu.com')
opener2.open('http://www.baidu.com')
# 将Cookie保存成Mozilla格式
cookie1.save(ignore_discard=True,ignore_expires=True)
# 将Cookie保存成LWP格式
cookie2.save(ignore_discard=True,ignore_expires=True)

ps2 = '''运行的结果会生成Cookie1和Cookie2的两种Cookie格式文件'''

在获得服务端发送过来的Cookie后,当爬虫再次访问服务端是,一般需要将这些Cookie原封不动再发送给服务端,
所以就需要从Cookie文件中读取Cookie,然后将这些Cookie发送给服务端,需要用到load()方法

3.10 LoadCookie

创建一个名为cookies.txt的文件,并自定义2个Cookie,
然后通过load方法安装在cookies.txt文件中的Cookie,并发给3.8.1的CookieServer
注意此案例需要启动3.8.1的Server服务器

import http.cookiejar,urllib.request
filename = 'cookies.txt'
cookie = http.cookiejar.LWPCookieJar()
# 装载cookies.txt文件,由于使用了LWPCookieJar读取Cookie,所以Cookie文件必须是LWP格式
cookie.load(filename,ignore_discard=True,ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://127.0.0.1:5000/readCookie')
print(response.read().decode('utf-8'))

3.11 UrlError

向不同服务器发送多个请求,并用URLError类捕捉发生的异常

ps = '''本例向不同服务器发送多个请求,并用URLError类捕捉发生的异常'''
from urllib import request,error
try:
    response = request.urlopen('http://www.jd123.com/test.html')
except error.URLError as e:
    # Bad Request 坏的请求头
    print(e.reason)
try:
    response = request.urlopen('https://geekori.com/abc.html')
except error.URLError as e:
    # Not Found 资源无法访问
    print(e.reason)
try:
    response = request.urlopen('https://geekori123.com/abc.html')
except error.URLError as e:
    # [Errno 8] nodename nor servname provided, or not known 
    print(e.reason)
try:
    response = request.urlopen('https://bbbccc.com',timeout=2)
except error.URLError as e:
    # time out 超时
    print(e.reason)

3.12 HTTPError

HTTPError是URLError的子类,专门用于处理HTTP请求错误,如400、404错误,该类的三个属性
1、code:返回HTTP状态码
2、reason:用于返回错误原因
3、headers:返回请求头
由于HTTPError是子类,所以try catch中先用HTTPError捕捉异常,再用URLError捕捉异常

from urllib import request,error
import socket
try:
    response = request.urlopen('http://www.jd123.com/test.html')
except error.HTTPError as e:
    print(type(e.reason))
    print(e.reason,e.code,e.headers)
try:
    response = request.urlopen('https://bbbccc.com',timeout=2)
except error.HTTPError as e:
    print('error.HTTPError:',e.reason)
except error.URLError as e:
    print(type(e.reason))
    print('error.URLError:',e.reason)
    # 判断r.reason的类型是否为socket.timeout类
    if isinstance(e.reason,socket.timeout):
        print('超时错误')
else:
    print('成功发送请求')

3.13 urlparse解析url地址

urlparse函数用于拆分URL,有3个参数
1、url:必填参数,待解析的URL
2、scheme:可选,如果url没有协议,默认为空
3、allow_fragments:可选参数,表示是否忽略fragment部分,如果为False忽略,默认为True

# 公式:scheme://netloc/path;params?query#fragment
# 本例使用urlparse函数拆分了一个URL,并输出拆分后的各个部分,以及使用urlunparse函数合并不同的部分,组成完整的URL
from urllib.parse import urlparse,urlunparse

result = urlparse('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment')

print('scheme:',result.scheme)
print('netloc:',result.netloc)
print('path:',result.path)
print('params:',result.params)
print('query:',result.query)
print('fragment:',result.fragment)
print('-----------------')
# 拆分URL,指定默认的scheme,并且忽略fragment部分
result = urlparse('search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment',scheme='ftp',allow_fragments=False)

print('scheme:',result.scheme)
print('fragment:',result.fragment)

print('----------------')
# 合并不同的部分,组成一个完整的URL
data = ['https','search.jd.com','Searchprint','world','keyword=Python从菜鸟到高手&enc=utf-8','comment']

print(urlunparse(data))

3.14 urlsplit分割url地址

第二种分割url的方法,urlsplit()

from urllib.parse import urlsplit,urlunsplit
result = urlsplit('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment')

# 将URL拆分成5部分,并指定默认的scheme,以及不考虑fragment部分
print('scheme:',result.scheme)
print('netloc:',result.netloc)
print('path:',result.path)
print('query:',result.query)
print('fragment:',result.fragment)
print('-----------------')
result = urlsplit('search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment',scheme='ftp',allow_fragments=False)

# 将5部分合并成完整的URL
print('scheme:',result.scheme)
print('fragment:',result.fragment)

print('----------------')
data = ['https','search.jd.com','Searchprint;world','keyword=Python从菜鸟到高手&enc=utf-8','comment']

print(urlunsplit(data))

3.15 urljoin合成url地址

使用urljoin函数合成不同的部分,组成一个完整的URL。
urljoin函数的第1个参数是base_url,是一个基URL,只能设置scheme、netloc和path,第2个参数是url。
如果第2个参数不是一个完整的URL,将第2个参数的值加到第1个参数后面,自动添加斜杠(/)。
如果第2个参数是一个完整的URL,那么直接返回第2个参数的值

from urllib.parse import urljoin
# 输出https://www.jd.com/index.html
print(urljoin('https://www.jd.com','index.html'))
# 输出https://www.taobao.com
print(urljoin('https://www.jd.com','https://www.taobao.com'))
# 输出https://www.taobao.com/index.html
print(urljoin('https://www.jd.com/index.html','https://www.taobao.com/index.html'))
# 输出https://www.jd.com/index.php?name=Bill&age=30
print(urljoin('https://www.jd.com/index.php','?name=Bill&age=30'))
# 输出https://www.jd.com/index.php?name=Bill
print(urljoin('https://www.jd.com/index.php?value=123','?name=Bill'))

3.16 urlencode对url进行解码

中文转码后的格式是%xx,其中xx是2位十六进制数
urlencode函数接受一个字典类型,用于定义URl的参数

from urllib.parse import urlencode,urljoin
params = {
    'name':'王军',
    'country':'China',
    'age':30
}
base_url = 'https://www.google.com?'
# url = base_url + urlencode(params)
url = urljoin(base_url,'?' + urlencode(params))
print(url)
# https://www.google.com?name=%E7%8E%8B%E5%86%9B&country=China&age=30

3.17 quote和unquote

使用quote函数对URL中的参数编码,然后使用unquote函数进行解码

from urllib.parse import quote,unquote
keyword = '李宁'
# 对参数进行编码
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)
# 解码
url = unquote(url)
print(url)

3.18 parse_qs和parse_qsl拆解参数

parse_qs函数将多个参数拆成字典的形式,key是参数名,value是参数值,
parse_qsl函数返回一个列表,每个元素时一个包含2个元素的元组,第1个元素值表示key,第2个元素值表示value

from urllib.parse import parse_qs,parse_qsl
query = 'name=王军 & age=35'
# 输出{'name': ['王军 '], ' age': ['35']}
print(parse_qs(query))
# 输出[('name', '王军 '), (' age', '35')]
print(parse_qsl(query))
query = 'name=王军 & age=35 & name=Bill & age=30'
# 输出{'name': ['王军 '], ' age': ['35 ', '30'], ' name': ['Bill ']}
print(parse_qs(query))
# 输出[('name', '王军 '), (' age', '35 '), (' name', 'Bill '), (' age', '30')]
print(parse_qsl(query))

robots检查robot协议内容

当爬虫访问一个网站是,首先会检查这个网址根目录下是否存在robots.txt文件,
如果存在,爬虫就会根据该文件中定义的抓取范围来抓取Web资源。
如果这个文件并不存在,爬虫就会抓取整个网站所有可直接访问的页面

url = 'https://www.jianshu.com/robots.txt'
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
    'Host': 'www.jianshu.com',
}
req = request.Request(url=url, headers=headers)
# 抓取robots.txt文件的内容,并提交给parse方法进行分析
robot.parse( request.urlopen(req).read().decode('utf-8').split('\n'))
# 使用can_fetch方法判断是否可以抓取某一个页面
# 输出True
print(robot.can_fetch('*','https://www.jd.com'))
# 输出True
print(robot.can_fetch('*','https://www.jianshu.com/p/92f6ac2c350f'))
# 输出False
print(robot.can_fetch('*','https://www.jianshu.com/search?q=Python&page=1&type=note'))
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值