Python网络爬虫--urllib
本篇隨便記錄學習崔慶才老師編著的《Python3 網絡爬蟲開發實戰》以及urllib標準庫使用
urllib庫是Python內置的HTTP請求庫,包含四個模塊:
- request:最基本的HTTP請求模塊,可以用來模擬發送請求。
- error:異常處理模塊,包含request模塊HTTP請求過程拋出的異常
- parse:一個工具模塊,提供了許多URL處理的方法,比如拆、解析、合并等
- robotparser:主要用來識別網站的robot.txt文件,然后判斷網站哪些部分可以爬取
發送請求
urllib.request.urlopen()
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
- url:請求的網址,必選參數
- data:可選參數,如果設定,則該請求為POST請求方法。data必須為字節流數據(可用內置函數bytes()方法轉換為字節流),數據內容如果是字典,可以通過parse模塊的urlencode()方法將其轉換為url格式的字符串
- timeout:可選參數,設置請求超時時間,單位為秒
- cafile:可選參數,CA證書文件
- capath:CA證書路徑
- cadefault:python3中已經棄用
- context:可選參數,指定SSL設置,必須為ssl.SSLContext類型
import urllib.request import urllib.parsename = bytes(urllib.parse.urlencode({"name":"Jane"}),encoding = "utf-8") response = urllib.request.urlopen("https://www.python.org",data = name,timeout = 1)
urllib.request.Request()
urllib.request.open()方法可以實現最基本的請求,但是該方法中只有幾個參數,有時候不能滿足我們的要求。因此我們可以通過urllib.request.Request()構建一個請求
Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None) - url:必選參數,請求的網址
- data:可選參數,如果設定,則該請求為POST請求方法。data必須為字節流數據(可用內置函數bytes()方法轉換為字節流),數據內容如果是字典,可以通過parse模塊的urlencode()方法將其轉換為url格式的字符串
- headers:可選參數,請求頭
- origin_req_host:客戶端主機名稱或者IP地址
- unverifiable:用戶沒有足夠的權限接收這個請求的結果,默認為False,即我們有權限接收
- method:請求方法
from urllib import request,parseheaders = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36","accept-encoding":"gzip","Cookie":"_ga=GA1.2.1498502246.1545274514"} data = bytes(parse.urlencode({"Language":"Python"}),encoding = "utf-8") my_request = request.Request("https://www.python.org",headers = headers,data = data,method = "POST") response = request.urlopen(my_request)
handler和opener
常用的handler:
- HTTPDefaultErrorHandler:用于處理HTTP響應錯誤,錯誤都會拋出HTTPError類型的異常
- HTTPRedirectHandler:用于處理重定向
- HTTPCookieProcessor:用于處理Cookies
- ProxyHandler:用于設置代理,默認代理為空
- HTTPPasswordMgr:用于管理密碼,維護用戶名與密碼的表單
- HTTPBasicAuthHandler:用于管理認證,如果打開一個連接需要認真,那么可以用它來解決認證的問題
- HTTPHandler:用來用處URL
opener:
urllib.request.build_opener([handler,?...]):實例化一個opener,使用各種功能的處理器urllib.request.install_opener(opener)?:設定一個全局opener,即程序里所有的請求都調用該opener
自定義的一般步驟:
- 使用相關功能的Handle處理器,來創建特定功能的處理器對象
- 然后通過如request.build_opener()方法,來使用這些處理器對象,創建自定義opener對象
- 使用自定義的opener對象,調用其open()方法向服務器發送請求
from urllib import request http_handler = request.HTTPHandler() # 實例化一個具有處理url功能的處理器 my_opener = request.build_opener(http_handler) # 創建一個能使用該處理器的opener,此時該opener就具備了處理url功能 response = my_opener.open("https://www.python.org")
# 設置代理 from urllib import request my_proxy = {"http":"120.76.55.49:8088"} proxy_handler = request.ProxyHandler(my_proxy) proxy_opener = request.build_opener(proxy_handler) response = proxy_opener.open("https://www.python.org")#如果有多個代理 from urllib import request import random my_proxies = [{"http" : "124.88.67.81:80"},{"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"},{"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"}] proxy = random.choice(my_proxies) proxy_handler = request.ProxyHandler(proxy) proxy_opener = request.build_opener(proxy_handler) response = proxy_opener.open("https://www.python.org")
平時我們設置Cookies都是在輸入賬戶、密碼登錄之后,然后在瀏覽器保存這些信息(Cookies),然后再去查看源碼找到這個Cookies(抓包),然后將它加入到請求頭,根據源碼再構建的請求。
而用handler的話,對于python2來說可以用cookielib模塊和urllib.request.HTTPCookieProcessor來處理,對于cookielib模塊有四個對象。在python3中,替換為http.cookiejar庫,四個子類,同python2四個對象相同:
- CookieJar:管理HTTP cookie值、存儲HTTP請求生成的cookie、向傳出的HTTP請求添加cookie的對象。整個cookie都存儲在內存中,對CookieJar實例進行垃圾回收后cookie也將丟失。
- FileCookieJar:FileCookieJar(filename,delayload=None,policy=None):從CookieJar派生而來,用來創建FileCookieJar實例,檢索cookie信息并將cookie存儲到文件中。filename是存儲cookie的文件名。delayload為True時支持延遲訪問文件,即只有在需要時才讀取文件或在文件中存儲數據。
- MozillaCookieJar:MozillaCookieJar(filename, delayload=None, policy=None):從FileCookieJar派生而來,創建與Mozilla瀏覽器 cookies.txt兼容的FileCookieJar實例
- LWPCookieJar:LWPCookieJar(filename, delay=None, policy=None):從FileCookieJar派生而來,創建與libwww-perl標準的Set-Cookie3文件格式兼容的FileCookieJar實例。
python2中基本用法:
from urllib import request import cookielib cookiejar = cookielib.CookieJar() # 創建一個Cookiejar對象來保存cookie cookie_handler = request.HTTPCookieProcessor(cookiejar) # 創建一個cookie處理器對象 my_opener = request.build_opener(cookie_handler) # 創建一個opener來使用這個處理器 response = my_opener.open("https://www.baidu.com")
python3中基本用法(CookieJar()):
from urllib import request from http import cookiejarmy_cookiejar = cookiejar.CookieJar() # CookieJar()可以管理,儲存HTTP請求生成的cookie,我們把這個保存的cookie實例化 my_cookiehandler = request.HTTPCookieProcessor(my_cookiejar) # 創建一個處理cookiejar的處理器,也就是處理器處理這個cookie opener = request.build_opener(my_cookiehandler) # 創建一個opener,此時這個opener就包含了這個cookie response = opener.open("https://www.baidu.com")
大多數情況我們使用CookieJar(),但是如果需要同本地文件進行交互(也就是從本地讀取,或者在本地創建),那么可以使用MozillaCookieJar()和LWPCookieJar(),兩者用法一樣,只需要將MozillaCookieJar和LWPCookieJar名稱互換
from urllib import request from http import cookiejar my_cookiejar = cookiejar.MozillaCookieJar(file) # 創建一個符合Mozilla瀏覽器標準的cookiejar對象,叫做my_cookiejar,此時它是一個對象,一個MozillaCookieJar實例化對象。file,即我們要創建的cookie文件的文件名字 my_cookiehandler = request.HTTPCookieProsessor(my_cookiejar) # 創建一個處理這個cookiejar實例的處理器對象 openr = request.build_opener(my_cookiehandler) # 創建一個opener,來使用這個處理器對象 response = opener.open("https://www.baidu.com") # sava()將這個實例化對象my_cookiejar包含的cookies信息,保存成本地文件,文件名之前已經確定了。另外,還可以通過load()方法從一個文件導入cookies # save()方法中兩個參數,ignore_discard:保存需要被丟棄的cookies;ignore_expires:保存過期的cookies # 通過下面代碼可以發現本地電腦中創建了一個名為cookie的文本文件 my_cookiejar.save(ignore_discard = True,ignore_expires = True)
對于某些網站需要輸入賬戶、密碼才能訪問,此處我們可以用HTTPPasswordMgrWithDefaultReadlm(管理賬戶、密碼)、HTTPBasicAuthHandler
from urllib import request username = "Maria" password = "123456" np = request.HTTPPasswordMgrWithDefaultReadlm() # 創建一個賬戶密碼管理器對象 np.add_password(username,password) # 賬戶密碼管理器中加入賬戶密碼 auth_handler = request.HTTPBasicAuthHandler(np) # 創建一個驗證該賬戶密碼的處理器對象 opener = request.build_opener(auth_handler) response = opener.open("https://www.baidu.com")
異常
異常:urrlib庫的error模塊定義了由request模塊產生的異常,如果request模塊應用過程出現了問題,request模塊便會拋出error模塊定義的異常。即,error模塊能捕獲request模塊使用過程中出現的問題,error模塊主要有三類:
- ContentTooShortError
- HTTPError
- URLError
urllib.error.URLError
當各種處理器(handler)運行出現問題的時候,一般是沒有網絡連接或者是無法連接服務器處理器會拋出異常。它是OSError的子類,它具有一個屬性:reason
reason:這個錯誤的原因,它可以是一個字符信息或者是一個異常實
urllib.error.HTTPError
它是URLError的子類,這一種異常通常是連接服務器后,服務器響應出現問題,如返回錯誤信息或者重定向錯誤,網頁驗證錯誤等等。雖然它是一個異常,但是它也可以像非異常文件樣的函數方法一樣返回(像urlopen()方法返回值一樣),這在處理外部HTTPError非常有用,比如 說驗證請求錯誤。這個類包含三個屬性:code、reason、headers
code:HTTP狀態碼
reason:通常是一個字符串信息,解釋這個錯誤的原因
headers:導致HTTPError的HTTP請求后服務器返回的HTTP響應的頭部信息。
urllib.error.ContentTooShort
當urlretrieve()函數檢測到下載的數據量小于預期(這個預期在頭部信息,Content-Length給定)時,拋出該異常。其中,content屬性儲存著下載的(或刪減過后的)數據
from urllib import request from urllib import error try:response = request.urlopen("https://www.sdkfjla.com") except error.URLError as ue:print(ue.reson)print(ue) except error.HTTPError as he:print(he.code)print(he.reason)print(he.headers)print(he) except Exception as e:print(e)
?解析鏈接
urlparse()
將一個URL鏈接解析為6部分:<協議>://<域名>/<路徑>;<訪問參數>?<查詢條件>#<錨點>。結果返回包含6個元素的元組。
urlparse(url, scheme='', allow_fragments=True)Parse a URL into 6 components: <scheme>://<netloc>/<path>;<params>?<query>#<gragment> Return a 6-tuple: (scheme, netloc, path, params, query, fragment). Note that we don't break the components up in smaller bits (e.g. netloc is a single string) and we don't expand % escape.
- url:必選參數,即帶解析的URL
- scheme:默認的協議,如果待解析的URL不含協議信息,則會將該參數作為默認的協議
- allow_fragment:即是否忽略fragment。如果設置為False,則fragment則會被忽略,而原本該解析為fragment的這一部分會被解析為path、parameters或者query的一部分,fragment則顯示為空
from urllib import parse result = parse.urlparse("https://i.cnblogs.com/EditPosts.aspx?postid=10813489&update=1") print(type(result),result)
result1 = parse.urlparse("http://www .baidu .com/index .html;user?id=5#commen",allow_fragment = False)
print(result1)
運行結果:
<class 'urllib.parse.ParseResult'> ParseResult(scheme='https', netloc='i.cnblogs.com', path='/EditPosts.aspx', params='', query='postid=10813489&update=1', fragment='')
ParseResult(scheme='http', netloc='www,baidu.com', path='/index.html', params='user', query='5#commen', fragment='')
?urlunparse()
與urlparse()正好相反,構造一個URL鏈接,其接收的參數是一個可迭代對象,但是它的長度必須為6,否則會拋出參數數量不足或者過多的問題。
urlunparse(components) Put a parsed URL back together again. This may result in a slightly different, but equivalent URL,
if the URL that was parsed originally had redundant delimiters,
e.g. a ? with an empty query (the draft states that these are equivalent).
如:
from urllib import parsecomponents = ["http","www.baidu.com","index.html","user","id=5","comment"] URL = parse.urlunparse(components) print(URL)
運行結果為:
"http://www.baidu.com/index.html;user?id=5#comment"
urlsplit()
這個方法和urlparse()非常相似,只不過它不再單獨解析params這部分,只返回5個結果。
from urllib import parse result = parse.urlsplit("http://www .baidu .com/index .html;user?id=5#commen") print(result)
運行結果:
SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')
urlunsplit()
該方法與urlunparse()非常相似,正好與urlsplit()相反。將鏈接各組分組合成一個完整的鏈接,傳入的參數是一個可迭代對象,但是長度必須為5
from urllib import parse components = ("http","www.baidu.com","/index.html;name=Jane","id=5","comment") URL = parse.urlunsplit(components) print(URL)
運行結果:
http://www.baidu.com/index.html;name=Jane?id=5#comment
urljoin()
urljoin(base, url, allow_fragments=True)Join a base URL and a possibly relative URL to form an absolute interpretation of the latter.
- base:基礎鏈接
- url:待構建的一個鏈接
- allow_fragment:是否包含錨點
首先提供一個基礎鏈接作為第一個參數,將一個新鏈接作為第二個參數,該方法會分析基礎鏈接的scheme、netloc、path這三個部分內容,然后根據這三個組分對新鏈接中的缺失部分進行補充,讓后者形成一個完整的鏈接
from urllib import parse URL = parse.urljoin("https://www.baidu.com","/index.html;name=Jane?id=2#comment") print(URL)
運行結果:
https://www.baidu.com/index.html;name=Jane?id=2#comment
urlencode()
常用來構建GET請求參數,即標準鏈接中的params組分。為了方便我們常會現用字典表示參數,然后用該方法將它構建為URL中的params組分。
from urllib import parse infomation = {"Maria":15,"Jane":16,"Mecheal":16} base_url = "https://www.baidu.com?" new_url = base_url+parse.urlencode(infomation) print(new_url)
運行結果:
https://www.baidu.com?Maria=15&Jane=16&Mecheal=16
parse_qs()
反序列化,假如我們有一串GET請求參數,利用parse_qs()方法,我們可以將這些參數轉回為字典
from urllib import parse params = "Maria=15&Jane=16&Mecheal=16" print(parse.parse_qs(params))
運行結果:
{'Maria': ['15'], 'Jane': ['16'], 'Mecheal': ['16']} parse_qsl()
同parse_qs()方法相似,只是parse_qsl()方法是將請求參數轉化為元組組成的列表
from urllib import parse params = "Maria=15&Jane=16&Mecheal=16" print(parse.parse_qsl(params))
運行結果:
[('Maria', '15'), ('Jane', '16'), ('Mecheal', '16')]
quote()
該方法可以將內容轉化為URL編碼,如URL中帶有中文參數時,可能會出現亂碼問題,我們可以用該方法將中文字符轉換為URL編碼
from urllib import parse keyword = "馮寶寶" url = "https://www.baidu.com/seach?wd="+parse.quote(keyword) print(url)
運行結果:
https://www.baidu.com/seach?wd=%E5%86%AF%E5%AE%9D%E5%AE%9D
unquote()
與quote()方法相反,unquote()方法可以將URL中的中文編碼解析還原為中文
from urllib import parse url = "https://www.baidu.com/seach?wd=%E5%86%AF%E5%AE%9D%E5%AE%9D" print(parse.unquote(url))
運行結果:
https://www.baidu.com/seach?wd=馮寶寶
解析Robots協議
Robots協議,全稱為網絡爬蟲排除標準(Robots Exclusion Protocol),用來告訴爬蟲或者搜索引擎哪些頁面可以抓取,哪些頁面不可以抓取。通常是一個Robots.txt文件,一般放在網站的根目錄下
robotparser.RobotFileParser類
該類提供了很多方法:
- can_fetch(self, useragent, url):返回的內容是該搜索引擎是否可以抓取這個 URL ,返回結果是 True 或 False
- modified(self):將當前時間設置為上次抓取和分析robot.text文件的時間
- mtime(self):返回的是上次抓取和分析robot.text文件的時間
- parse(self, lines):用來解析 robots. txt 文件,傳人的參數是 robots .txt某些行的內容 ,它會按照 robots . txt的語法規則來分析這些內容?
- read(self):讀取 robots . txt 文件并進行分析 。 注意,這個方法執行一個讀取和分析操作,如果不調用這個方法 , 接下來的判斷都會為 False ,所以一定記得調用這個方法 。 這個方法不會返回任何內容,但是執行了讀取操作?
from urllib.robotparser import RobotFileParser rp = RobotFileParser() # 對RobotFileParser類實例化 rp.set_url("https://www.taobao.com/robots.text") # 設置robot.txt文件鏈接 rp.read() #讀取該robot.txt文件并分析 # 分析我們是否能抓取該網站的某個頁面 print(rp.can_fetch("*","https://www.taobao.com/markets/3c/tbdc?spm=a21bo.2017.201867-main.12.5af911d9DPQkf4"))
運行結果:
False
?
轉載于:https://www.cnblogs.com/sakura-d/p/10813489.html
總結
以上是生活随笔為你收集整理的Python网络爬虫--urllib的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 钟点工一小时多少钱啊?
- 下一篇: 淬毒魔刃