爬虫之urllib模块

请求 urllib.request

urlopen

  • 默认发起get请求,当请求中传入data参数时,则会发起post请求
from urllib import request

resp = request.urlopen(url, 
					   data=None, 
					   [timeout, ]*, 
					   cafile=None, 
					   capath=None, 
					   cadefault=False, 
					   context=None)

(1)url:要请求的网址

www.baidu.com
  • 在url中,是只能使用ASCII中包含的字符的,也就是说,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我们有时候又有将中文字符加入到url中的需求,例如百度的搜索地址:https://www.baidu.com/s?wd=机械舞
>>> from urllib import parse
>>> keyword = "机械舞"
>>> data = parse.quote(keyword)
>>> data
'%E6%9C%BA%E6%A2%B0%E8%88%9E'
>>> parse.unquote(data)
'机械舞'
>>> 
from urllib import request
from urllib import parse

url = 'https://www.baidu.com/s?'

keywords = input("请输入要查询的内容:")
data = parse.quote(keywords)

fullurl = url + "wd="+data
  • 在访问url时,我们常常需要传递很多的url参数,而如果用字符串的方法去拼接url的话,会比较麻烦,所以urllib中提供了urlencode这个方法来拼接url参数
>>> keyword = {"wd": "机械舞"}
>>> data = parse.urlencode(keyword)
>>> data
'wd=%E6%9C%BA%E6%A2%B0%E8%88%9E'
from urllib import request
from urllib import parse

url = 'https://www.baidu.com/s?'

keywords = input("请输入要查询的内容:")
kw = {"wd": keywords}

kw = parse.urlencode(kw)
# 将查询关键字进行url编码
fullurl = url + kw

resp = request.urlopen(fullurl)
resp.read().decode()

在这里插入图片描述

(2)data:请求需要参数

  • urllib库中orlopen方法中请求参数data要求为bytes格式
from urllib import parse
from urllib import request

url = 'wwww.taobao.com/login'

formdata = {
	"username": "admin",
	"password": "admin123"
}

data = parse.urlencode(formdata).encode('utf-8')
或
data = bytes(parse.urlencode(formdata), encoding='utf-8')

resp = request.urlopen(url, data=data)
resp.read().decode()

(3)timeout:超时时间(单位:秒)

  • 在某些网络情况不好或者服务器端异常的情况会出现请求慢的情况,或者请求异常,所以这个时候我们需要给请求设置一个超时时间,而不是让程序一直在等待结果,如果请求时间超出,那么就会抛出异常。
resp = request.urlopen(url, data=data, timeout=0.2)
resp.read().decode()
  • 此时我们需要对异常进行捕获
import socket
from urllib import request
from urllib import error

try:
    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

(4)context:CA认证忽略

  • HTTPS请求和HTTP请求,HTTPS = HTTP+SSL(安全套接层:RSA算法加密传输)
  • HTTPS协议网站一般是经过权威机构CA认证机构认证过的安全性很高的网站
  • 而有些网站并未经过CA安全认证(比如12306),因此当我们访问时,浏览器会提示我们存在安全风险,当我们很确信该网站值得信赖时,我们可以手动忽略该提示,那么在使用爬虫访问时我们就不能再手动处理提示了,此时就可以通过设置进行忽略该风险。
import ssl

# 创建一个不需要认证的ssl上下文管理器
context = ssl._create_unverified_context()
resp = request.urlopen(url, data=data, timeout=0.2, context=context)

Request

  • urlopen只能用于一些简单的请求,因为它无法添加一些header信息,如果后面写爬虫我们可以知道,很多情况下我们是需要添加头部信息去访问目标站的,这个时候就用到了Request

(1)设置Headers

  • 有很多网站为了防止程序爬虫爬网站造成网站瘫痪,会需要携带一些headers头部信息才能访问,最长见的有user-agent参数
from urllib import request

url = 'http://www.jd.com'

headers = {
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
    'Host': 'httpbin.org'
}

formdata = {
    'name': 'zhaofan'
}

data = bytes(parse.urlencode(formdata), encoding='utf8')
# 通过Request设置请求头信息
req = request.Request(url=url, data=data, headers=headers)
response = request.urlopen(req)
print(response.read().decode('utf-8'))
  • 第二种设置headers的方法
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')
  • 一个自动生成请求头的库
from fake_useragent import UserAgent

ua = UserAgent()
headers = {"User-Agent": ua} 

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

(2)设置cookie

  • cookie中保存中我们常见的登录信息,有时候爬取网站需要携带cookie信息访问,这里用到了http.cookijar,用于获取cookie以及存储cookie
from http import cookiejar
from urllib import request
from urllib import parse
from fake_useragent import UserAgent

ua = UserAgent()
headers = {"User-Agent": ua}

# 创建cookiejar对象,用来获取cookie并保存
cj = cookiejar.CookieJar()

# 通过HTTPCookieProcess对象来管理cj对象
cookie_handler = request.HTTPCookieProcess(cj)
  • 为了在请求时能带上Cookie信息,我们需要重新构造一个opener
  • 使用request.build_opener方法来进行构造opener,将我们想要传递的cookie配置到opener中,然后使用这个opener的open方法来发起请求。
# 构建一个opener,一个新的可以处理cookie的handler,取代原来默认的http handler,从而加强http handler的功能,实现其可以处理cookie
opener = request.build_opener(cookie_handler)
# 可以通过addheaders来添加请求头信息
# opener.addheaders = [('User-Agent': 'Mozilla/5.0....')]

# 构建请求所需数据
url = 'http://www.weixin.com'
formdata = {"username": "admin",
		"password": "admin123"}
data = pares.urlencode(formdata).encode('utf-8')
req = request.Request(url=url, data=data, headers=headers)

# 通过open方法发起请求
resp = opener.open(req)
# 根据响应判断是否登录成功
# 假如现在登录成功,我们要去向登陆成功后的其他页面抓取数据,再次发送请求
# 通过Request对象构建数据,open方法发起请求
response = opener.open("http://www....")
# 写入文件
with open("xxxx", 'wb') as f:
	f.write(response.read())
  • 或者也可以把这个生成的opener使用install_opener方法来设置为全局的。则之后使用urlopen方法发起请求时,都会带上这个cookie。
# 将这个opener设置为全局的opener
request.install_opener(opener)
resp = request.urlopen(url)

(2)启用代理ProxyHandler

import urllib.request

proxy_handler = urllib.request.ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('http://httpbin.org/get')

print(response.read())

(3)下载数据到本地

  • 在我们进行网络请求时常常需要保存图片或音频等数据到本地,一种方法是使用python的文件操作,将read()获取的数据保存到文件中。
  • 而urllib提供了一个urlretrieve()方法,可以简单的直接将请求获取的数据保存文件
from urllib import request

url = 'http://python.org/'
request.urlretrieve(url, 'python.html')

响应 urllib.response

(1)read()

  • 获取响应返回的数据,只能使用一次

(2)getcode()

  • 获取服务器返回的状态码。

(3)getheaders()

  • 获取返回响应的响应报头。

(4)geturl()

  • 获取访问的url

异常处理

(1)urllib.error

  • 在很多时候我们通过程序访问页面的时候,有的页面可能会出现错误,类似404,500等错误
    这个时候就需要我们捕捉异常,下面先写一个简单的例子
from urllib import request, error

try:
    response = request.urlopen("http://jdsogf.com/index")
except error.URLError as e:
    print(e.reason)
  • 上述代码访问的是一个不存在的页面,通过捕捉异常,我们可以打印异常错误

(2)这里我们需要知道的是在urllb异常这里有两个个异常错误:

  • URLError
  • HTTPError
  • HTTPError是URLError的子类
  • URLError里只有一个属性:reason,即抓异常的时候只能打印错误信息,类似上面的例子
  • HTTPError里有三个属性:code,reason,headers,即抓异常的时候可以获得code,reson,headers三个信息,例子如下
from urllib import request, error
try:
    response = request.urlopen("http://pythonsite.com/1111.html")
except error.HTTPError as e:
    print(e.reason)
    print(e.code)
    print(e.headers)
except error.URLError as e:
    print(e.reason)

else:
    print("reqeust successfully")
  • 同时,e.reason其实也可以在做深入的判断,例子如下:
import socket

from urllib import request, error

try:
    response = request.urlopen("http://www.pythonsite.com/",timeout=0.001)
except error.URLError as e:
    print(type(e.reason))
    if isinstance(e.reason, socket.timeout):
        print("time out")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值