1 urllib庫
參考連接:
https://zhuanlan.zhihu.com/p/412408291
1.1 urllib概述
1.1.1 urllib簡介
Urllib是python內(nèi)置的一個http請求庫,不需要額外的安裝。只需要關注請求的鏈接,參數(shù),提供了強大的解析功能
Urllib庫有四個模塊:request,error, parse, robotparser
request:發(fā)起請求(重要)
error:處理錯誤
parse:解析RUL或目錄等
robotparser(不怎么用):解析網(wǎng)站的robot.txt
1.1.2 urllib的robotparser模塊
Robots協(xié)議也稱作爬蟲協(xié)議、機器人協(xié)議,它的全名是網(wǎng)絡爬蟲排除標準(RobotsExclusingProtocol),主要用來告訴爬蟲和搜索引擎哪些網(wǎng)頁可以抓取,哪些網(wǎng)頁不可以抓取。該協(xié)議的內(nèi)容通常存放在名叫robots.txt的文本文件中,這個文件一般位于網(wǎng)站的根目錄下。
User-agent后的*表示該規(guī)則對所有的爬蟲有效;/robot目錄不允許訪問,僅允許訪問/test/print目錄
看一下淘寶的robots.txt
https://www.taobao.com/robots.txt
User-agent: Baiduspider
Disallow: /
User-agent: baiduspider
Disallow: /
基于robots查看是否可以爬取
from urllib.robotparser import RobotFileParser
robot=RobotFileParser() # 創(chuàng)建一個解析器,用來存儲Robots協(xié)議內(nèi)容
robot.set_url('https://www.taobao.com/robots.txt') # set_url()用于設置robots.txt文件的路徑
robot.read() # //read()用于讀取并分析robots.txt文件的內(nèi)容,并把結(jié)果存儲到解析器中
print(robot) # 輸出robot協(xié)議
print("*"*10)
print(robot.can_fetch('*','https://www.taobao.com/test.js')) # can_fetch()用于判斷指定的搜索引擎是否能抓取這個URL
print(robot.can_fetch('Baiduspider','https://www.taobao.com/test.js'))
輸出為:
User-agent: Baiduspider
Disallow: /
User-agent: baiduspider
Disallow: /
**********
True
False
1.1.3 request模塊
請求方法
urllib.request.urlopen(url, data=None, [timeout, ]*)
url:地址,可以是字符串,也可以是一個Request對象
data:請求參數(shù)
timeout:設置超時
"""
# 爬蟲就是模擬用戶,向服務器發(fā)起請求,服務器會返回對應數(shù)據(jù)
# 數(shù)據(jù)抓包,使用chrome,盡量不要使用國產(chǎn)瀏覽器
# F12打開界面,點擊network,刷新,會顯示網(wǎng)頁的請求,常見的請求有GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE,其中GET 和 POST 最常用
# GET請求把請求參數(shù)都暴露在URL上
# POST請求的參數(shù)放在request body,一般會對密碼進行加密
# 請求頭:用來模擬一個真實用戶
# 相應狀態(tài)碼:200表示成功
推薦一個測試網(wǎng)站,用于提交各種請求:http://httpbin.org/,該網(wǎng)站的更多的用法自行搜索
"""
# 引入請求模塊
import urllib.request
# 發(fā)起請求,設置超時為1s
response = urllib.request.urlopen('http://httpbin.org/', timeout = 1)
print(response.status) # 狀態(tài)碼,判斷是否成功,200
print(response.getheaders()) # 響應頭 得到的一個元組組成的列表
print(response.getheader('Server')) #得到特定的響應頭
print(response.getheader('User-Agent')) #得到特定的響應頭
# 使用read()讀取整個頁面內(nèi)容,使用decode('utf-8')對獲取的內(nèi)容進行編碼
print(response.read().decode('utf-8'))
輸出為:
200
[('Date', 'Fri, 22 Sep 2023 01:23:18 GMT'), ('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '9593'), ('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true')]
gunicorn/19.9.0
None
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>httpbin.org</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700"
rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/flasgger_static/swagger-ui.css">
<link rel="icon" type="image/png" href="/static/favicon.ico" sizes="64x64 32x32 16x16" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
...
</body>
</html>
POST請求
import urllib.parse
import urllib.request
# data需要的是字節(jié)流編碼格式的內(nèi)容,此時請求方式為post
data = bytes(urllib.parse.urlencode({"name": "WenAn"}), encoding= 'utf-8')
response = urllib.request.urlopen('http://httpbin.org/post', data= data)
print(response.read().decode('utf-8'))
輸出為:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "WenAn"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "10",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.10",
"X-Amzn-Trace-Id": "Root=1-650ced1b-365667a33f287edd7b5579ab"
},
"json": null,
"origin": "120.194.158.199",
"url": "http://httpbin.org/post"
}
通過返回的內(nèi)容可以返現(xiàn)包含了User-Agent數(shù)據(jù),這是因為瀏覽器發(fā)起請求時都會有請求頭header,但urlopen無法添加其他參數(shù),這會讓服務器識別出我們是一個爬蟲,因此我們需要聲明一個request對象來添加header
import urllib.request
import urllib.parse
url = 'http://httpbin.org/post'
# 添加請求頭
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', 'Host':'httpbin.org'}
dict = {
'name':'WenAn'
}
data = bytes(urllib.parse.urlencode(dict), encoding = 'utf-8')
request = urllib.request.Request(url, data=data, headers=headers, method='POST')
response = urllib.request.urlopen(request)
# response = urllib.request.urlopen('http://httpbin.org/post', data= data)
print(response.read().decode('utf-8'))
輸出為:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "WenAn"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "10",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-650cee11-094d85e314f07a847244a399"
},
"json": null,
"origin": "120.194.158.199",
"url": "http://httpbin.org/post"
}
輸出的數(shù)據(jù)中User-Agent值為
“Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36”
urlretrieve將數(shù)據(jù)下載到本地
import urllib.request
urllib.request.urlretrieve("https://www.youdao.com","youdao.html")
urllib.request.urlretrieve("https://www.httpbin.org/get","httpbin/get.html")
from urllib import request, error
#導入request和error模塊
def schedule(num,size,tsize):
"""
回調(diào)函數(shù),num:當前已經(jīng)下載的塊;
size:每次傳輸?shù)膲K大小;
tsize:網(wǎng)頁文件總大小
"""
if tsize == 0:
percent = 0
else:
percent = num * size / tsize
if percent > 1.0:
percent = 1.0
percent = percent * 100
print("\r[%-100s] %.2f%%" % ('=' * int(percent), percent),end='')
url = "https://oimageb3.ydstatic.com/image?\
id=5951384821510112623&product=xue" # 下載文件的url
path = r"img1.jpg"
# 文件下載后保存的本地路徑
request.urlretrieve(url, path, schedule)
print('\r\n' + url + ' download successfully!')
輸出為:
1.1.4 Error
以上講述的是使用urlopen發(fā)送請求的過程,而且是正常情況下的情形。若是非正常情況,比如url地址是錯誤的或者網(wǎng)絡不通,那么就會拋出異常。當有異常發(fā)生時,需要利用python的異??刂茩C制,也就是使用try…except語句來捕獲異常進行處理,否則程序就會異常退出。在使用try…except時,except子句一般會加上錯誤類型,以便針對不同的錯誤類型采取相應的措施。
Error模塊下有三個異常類:
URLError
處理程序在遇到問題時會引發(fā)此異常(或其派生的異常)只有一個reason屬性
HTTPError
是URLError的一個子類,有更多的屬性,如code, reason,headers適用于處理特殊 HTTP 錯誤例如作為認證請求的時候。
ContentTooShortError
此異常會在 urlretrieve() 函數(shù)檢測到已下載的數(shù)據(jù)量小于期待的數(shù)據(jù)量(由 Content-Length 頭給定)時被引發(fā)。 content 屬性中將存放已下載(可能被截斷)的數(shù)據(jù)。
from urllib import request, error
try:
# 打開httpbin里面的a.html頁面,因為它根本不存在,所以會拋出異常
response = request.urlopen('http://httpbin.org/a.html')
except error.URLError as e:
print(e.reason) #Not Found
輸出為:
NOT FOUND
HTTPError案例
# 把URLError換成了HTTPError
from urllib import request, error
try:
# 打開httpbin里面的a.html頁面,因為它根本不存在,所以會拋出異常
response = request.urlopen('http://httpbin.org/a.html')
except error.HTTPError as e:
print(e.reason)
print(e.code)
print(e.headers)
輸出為:
NOT FOUND
404
Date: Fri, 22 Sep 2023 01:40:11 GMT
Content-Type: text/html
Content-Length: 233
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
1.1.5 parse模塊
Parse模塊
parse模塊定義了url的標準接口,實現(xiàn)url的各種抽取,解析,合并,編碼,解碼
編碼
urlencode()介紹—參數(shù)編碼
它將字典構(gòu)形式的參數(shù)序列化為url編碼后的字符串,在前面的request模塊有用到
import urllib.parse
dict = {
'name':'WenAn',
'age': 20
}
params = urllib.parse.urlencode(dict)
print(params)
輸出為:
name=WenAn&age=20
quote()介紹—中文URL編解碼
import urllib.parse
params = '少年強則國強'
base_url = 'https://www.baidu.com/s?wd='
url = base_url + urllib.parse.quote(params)
print(url)
# https://www.baidu.com/s?wd=%E5%B0%91%E5%B9%B4%E5%BC%BA%E5%88%99%E5%9B%BD%E5%BC%BA
# 使用unquote()對中文解碼
url1 = 'https://www.baidu.com/s?wd=%E5%B0%91%E5%B9%B4%E5%BC%BA%E5%88%99%E5%9B%BD%E5%BC%BA'
print(urllib.parse.unquote(url1))
# https://www.baidu.com/s?wd=少年強則國強
中文在字典中案例
from urllib import parse
from urllib import request
url='http://www.baidu.com/s?'
dict_data={'wd':'百度翻譯'}
#unlencode() 將字典{k 1:v 1,k2:v2}轉(zhuǎn)化為k1=v1&k2=v2
url_data=parse.urlencode(dict_data)
#urldata:wd=%E7%99%BE%E5%BA%A6%E7%BF%BB%E8%AF%91
print(url_data)#讀取URL響應結(jié)果
res_data=request.urlopen((url+url_data)).read()#用utf 8對響應結(jié)果編碼
data=res_data.decode('utf-8')
print(data)
輸出為:
wd=%E7%99%BE%E5%BA%A6%E7%BF%BB%E8%AF%91
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>百度安全驗證</title>
...
</head>
<body>
...
</body>
</html>
在爬取過程中,當獲得一個URL時,如果想把這個URL中的各個組成部分分解后使用,那么就要用到url.parse()和url.split()。
使用urlparse()進行URL的解析
from urllib import parse
url = "http://www.youdao.com/s?username=spider"
result = parse.urlparse(url)
print ("urlparse解析出來的結(jié)果:\n%s"%str(result))
輸出為:
urlparse解析出來的結(jié)果:
ParseResult(scheme='http', netloc='www.youdao.com', path='/s', params='', query='username=spider', fragment='')
urlsplit()方法和urlparse()方法的作用相似,區(qū)別在于它不再單獨解析params部分,而僅返回5個結(jié)果,將params合并到path中。
使用urlsplit()進行URL的解析。
from urllib import parse
url = "http://www.youdao.com/s?username=spider"
result = parse.urlsplit(url)
print ("urlsplit解析出來的結(jié)果:\n%s"%str(result))
輸出為:
urlsplit解析出來的結(jié)果:
SplitResult(scheme='http', netloc='www.youdao.com', path='/s', query='username=spider', fragment='')
1.1.6 百度翻譯案例
import urllib.request
import urllib.parse
url = 'https://fanyi.baidu.com/sug'
header = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"
}
keyword = input('請輸入您要查詢的單詞\n')
data = { 'kw':keyword}
data = urllib.parse.urlencode(data).encode('utf‐8')
request = urllib.request.Request(url=url,headers=header,data=data)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
輸出為:
請輸入您要查詢的單詞
你好
{“errno”:0,“data”:[{“k”:“\u4f60\u597d”,“v”:“hello; hi; How do you do!”},{“k”:“\u4f60\u597d\u5417”,“v”:“How do you do?”},{“k”:“\u4f60\u597d\uff0c\u964c\u751f\u4eba”,“v”:“[\u7535\u5f71]Hello Stranger”}],“l(fā)ogid”:2836022906}
1.2 urllib高級應用
1.2.1Opener
opener是 urllib.request.OpenerDirector 的實例,如上文提到的urlopen便是一個已經(jīng)構(gòu)建好的特殊opener,但urlopen()僅提供了最基本的功能,如不支持代理,cookie等
自定義Opener的流程
使用相關的 Handler處理器來創(chuàng)建特定功能的處理器對象通過 urllib.request.build_opener()方法使用處理器對象,
創(chuàng)建自定義opener對象使用自定義的opener對象,
調(diào)用open()方法發(fā)送請求
關于全局Opener
如果要求程序里面的所有請求都使用自定義的opener,使用urllib.request.install_opener()
import urllib.request
# 創(chuàng)建handler
http_handler = urllib.request.HTTPHandler()
# 創(chuàng)建opener
opener = urllib.request.build_opener(http_handler)
# 創(chuàng)建Request對象
request = urllib.request.Request('http://httpbin.org/get')
# 局部opener,只能使用.open()來訪問
# response = opener.open(request)
# 全局opener,之后調(diào)用urlopen,都將使用這個自定義opener
urllib.request.install_opener(opener)
response = urllib.request.urlopen(request)
print(response.read().decode('utf8'))
輸出為:
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.10",
"X-Amzn-Trace-Id": "Root=1-650cf628-059816f8524cf7ec7d9cee6e"
},
"origin": "120.194.158.199",
"url": "http://httpbin.org/get"
}
1.2.2 代理設置
推薦幾個提供免費代理服務的網(wǎng)站:
http://www.xiladaili.com/
https://www.kuaidaili.com/free/
https://ip.jiangxianli.com/?page=1文章來源:http://www.zghlxwxcb.cn/news/detail-731364.html
import urllib.request
# 創(chuàng)建handler
proxy_handler = urllib.request.ProxyHandler({
'http': 'http://182.34.103.79:9999'
})
# 創(chuàng)建opener
opener = urllib.request.build_opener(proxy_handler)
header = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"
}
request = urllib.request.Request('https://www.httpbin.org/get', headers=header)
# 配置全局opener
urllib.request.install_opener(opener)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
代理設置未成功文章來源地址http://www.zghlxwxcb.cn/news/detail-731364.html
到了這里,關于Python爬蟲技術(shù)系列-01請求響應獲取-urllib庫的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!