使用 urllib 模組下載網頁
使用 urllib 模組下載網頁
前言
urllib模組是 Python 內建下載網頁資訊的模組,它包含下列4個主要模組:
- request 模組 : 可開啟指定網址的HTML文件內容。
- parse 模組 : 可解飢 URL。
- error 模組 : 內有 urllib.request() 物件發生錯誤或異常的原因。
- robotparse 模組 : 可議解析 robots.txt 文件。
大綱
- urllib.request 打開和讀取URL
- http.client.HTTPResponse 物件屬性
- 使用urllib.request.urlretrieve()下載圖片
- urllib.parse 用於解析 URL
- urllib.error 異常處理
- urllib.robotparser 用於解析 robots.txt 文件
urllib.request 打開和讀取URL
urllib.request 模塊定義了適用於在各種複雜情況下打開 URL(主要為 HTTP)的函數和類別, 例如基本認證、摘要認證、重定向、cookies 及其它。
範例 pythonUrllib-01.py : 利用 urllib.request.urlopen() 讀取網頁,印出所回傳的的資料形態與內容
# pythonUrllib-01.py import urllib.request url = 'https://tw.finance.yahoo.com/' htmlfile = urllib.request.urlopen(url) print(type(htmlfile)) print(htmlfile)
執行結果
<class 'http.client.HTTPResponse'>
<http.client.HTTPResponse object at 0x00000249F14D4A60>
範例 pythonUrllib-02.py : 利用 urlopen() 讀取網頁,回傳的的資料形態為 http.client.HTTPResponse,可使用 read()讀取,但是中文內容以二進位顯示
# pythonUrllib-02py import urllib.request url = 'https://tw.finance.yahoo.com/' htmlfile = urllib.request.urlopen(url) print(htmlfile.read())
執行結果
b'<!DOCTYPE html><html id="atomic" class="NoJs desktop" lang="zh-Hant-TW"><head prefix="og: http://ogp.me/ns#"><script>window.performance && window.performance.mark && window.performance.mark(\'PageStart\');</script><meta charSet="utf-8"/><meta property="og:type" content="website"/><meta property="og:description" content="Yahoo\xe5\xa5\x87\xe6\x91\xa9\xe8\x82\xa1\xe5\xb8\x82\xe6\x8f\x90\xe4\xbe\x9b\xe5\x9c\x8b\xe5\x85\xa7\xe5\xa4\x96\xe8\xb2\xa1\xe7\xb6\x93\xe6\x96\......
範例 pythonUrllib-03.py : 延續 範例 pythonUrllib-02.py,但是中文內容以二進位顯示,使用 decode('utf-8') 方法處理。
# pythonUrllib-03.py import urllib.request url = 'https://tw.finance.yahoo.com/' htmlfile = urllib.request.urlopen(url) print(htmlfile.read().decode('utf-8'))
執行結果
<!DOCTYPE html><html id="atomic" class="NoJs desktop" lang="zh-Hant-TW"><head prefix="og: http://ogp.me/ns#"><script>window.performance && window.performance.mark && window.performance.mark('PageStart');</script><meta charSet="utf-8"/><meta property="og:type" content="website"/><meta property="og:description" content="Yahoo奇摩股市提供國內外財經新聞,台股、期貨、選擇權、國際指數 、外匯、港滬深股、美股等即時報價資訊,以及自選股、......
urlopen(url, timeout=30) 另外有個參數 timeout 預設是 20秒,開啟網頁逾時會跳出異常。
http.client.HTTPResponse 物件屬性
從上述,我們了解開啟網頁後會傳回 http.client.HTTPResponse 物件,接著我們來介紹幾個此物件常用的屬性。
- HTTPResponse.version : 版本編號。
- TTPResponse.url : 物件的 URL。 (HTTPResponse.geturl(),3.9 版後已棄用)
- HTTPResponse.status : 由服務器返回的狀態碼。(HTTPResponse.getstatus() 3.9 版後已棄用)
- HTTPResponse.getheaders() : 取得用 (header, value) 元組構成的串列方式保存的表頭 header 內容。
範例 pythonUrllib-04.py : http.client.HTTPResponse 物件常用的屬性。
# pythonUrllib-04.py import urllib.request url = 'https://tw.finance.yahoo.com/' htmlfile = urllib.request.urlopen(url) print('版本 : ', htmlfile.version) print('網址 : ', htmlfile.geturl()) print('下載 : ', htmlfile.status) print('表頭 : ') for header in htmlfile.getheaders(): print(header)
執行結果
版本 : 11
網址 : https://tw.finance.yahoo.com/
下載 : 200
表頭 :
('expect-ct', 'max-age=31536000, report-uri="http://csp.yahoo.com/beacon/csp?src=yahoocom-expect-ct-report-only"')
('referrer-policy', 'no-referrer-when-downgrade')
('strict-transport-security', 'max-age=31536000')......
使用urllib.request.urlretrieve()下載圖片
範例 pythonUrllib-05.py : 使用urllib.request.urlretrieve()下載圖片。
# pythonUrllib-05.py import urllib.request url_pict = 'http://www.python.org/images/success/nasa.jpg' fn = 'output-pythonUrllib-05.png' pict = urllib.request.urlretrieve(url_pict,fn)
執行結果
產生一個圖檔 output-pythonUrllib-05.png
urllib.parse 用於解析 URL
urllib.parse模組對資料內容進行格式處理,有以下幾個方法
- urllib.parse.quote(url):(URL編碼處理)主要對URL中的非ASCII碼編碼處理
- urllib.parse.unquote(url):(URL解碼處理)URL上的特殊字元還原
- urllib.parse.urlencode(data):對請求資料data進行格式轉換
我們用以下範例說明,詳細說明請參閱 Python 文件: urllib.parse 用於解析 URL。
範例 pythonUrllib-06.py : urllib.parse模組,中文的不同編碼方式 : URL編碼 和 UTF-8 。
# pythonUrllib-06.py from urllib import parse s = '台灣積體電路製造' url_code = parse.quote(s) print('URL編碼 : ', url_code) code = parse.unquote(url_code) print('中文編碼 : ', code)
執行結果
URL編碼 : %E5%8F%B0%E7%81%A3%E7%A9%8D%E9%AB%94%E9%9B%BB%E8%B7%AF%E8%A3%BD%E9%80%A0
中文編碼 : 台灣積體電路製造
範例 pythonUrllib-07.py : urllib.parse模組的6大組件 : scheme : URL協議, netloc : 網絡位置, path : 分層路徑, params : 最後路徑元素的參數, query : 查詢組件, fragment : 片段識別 。
# pythonUrllib-07.py from urllib import parse url = 'https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default' parse.urlparse = parse.urlparse(url) print(type(parse.urlparse)) print(parse.urlparse) print('scheme = ', parse.urlparse.scheme) print('netloc = ', parse.urlparse.netloc) print('path = ', parse.urlparse.path) print('params = ', parse.urlparse.params) print('query = ', parse.urlparse.query) print('fragment = ', parse.urlparse.fragment)
執行結果
<class 'urllib.parse.ParseResult'> ParseResult(scheme='https', netloc='docs.python.org', path='/3/search.html', params='', query='q=parse&check_keywords=yes&area=default', fragment='') scheme = https netloc = docs.python.org path = /3/search.html params = query = q=parse&check_keywords=yes&area=default fragment =.....
範例 pythonUrllib-08.py : 另外相似的模組 parse.urlsplit(url) 和 parse.urlparse(url) 最大不同是回傳部分沒有 params 元素。
# pythonUrllib-08.py from urllib import parse url = 'https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default' urp = parse.urlsplit(url) print(type(urp)) print(urp) print('scheme = ', urp.scheme) print('netloc = ', urp.netloc) print('path = ', urp.path) print('query = ', urp.query) print('fragment = ', urp.fragment)
執行結果
<class 'urllib.parse.SplitResult'> SplitResult(scheme='https', netloc='docs.python.org', path='/3/search.html', query='q=parse&check_keywords=yes&area=default', fragment='') scheme = https netloc = docs.python.org path = /3/search.html query = q=parse&check_keywords=yes&area=default fragment =...
範例 pythonUrllib-09.py : parse.urlsplit(url) 合成URL方法為 parse.urlunsplit(url),parse.urlparse(url) 合成URL方法為 parse.urlunparse(url)。
# pythonUrllib-09.py from urllib import parse scheme = 'https' netloc = 'docs.python.org' path = '/3/search.html' params = '' query = 'q=parse&check_keywords=yes&area=default' frament = '' url_unparse = parse.urlunparse((scheme,netloc,path,params,query,frament)) print(url_unparse) url_unsplit = parse.urlunsplit([scheme,netloc,path,query,frament]) print(url_unsplit)
執行結果
https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default
https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default
範例 pythonUrllib-10.py : 使用 parse.urlencode() 方法,將字典格式的資料轉化為網頁網址。
# pythonUrllib-10.py from urllib import parse url_python = 'https://docs.python.org/3/search.html?' query = { 'q':'parse', 'check_keywords':'yes', 'area':'default'} url = url_python + parse.urlencode(query) print(url)
執行結果
https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default
範例 pythonUrllib-11.py : 使用 parse.parse_qs() 方法,將網頁網址轉化為字典格式的資料。
# pythonUrllib-11.py from urllib import parse query_str = 'q=parse&check_keywords=yes&area=default' print('parse.parse_qs = ', parse.parse_qs(query_str)) print('parse.parse_qsl = ', parse.parse_qsl(query_str))
執行結果
parse.parse_qs = {'q': ['parse'], 'check_keywords': ['yes'], 'area': ['default']}
parse.parse_qsl = [('q', 'parse'), ('check_keywords', 'yes'), ('area', 'default')]
urllib.error 異常處理
爬取網頁異常時,可以使用 urllib.error 模組處理 urllib.request() 模組產生的異常, URLError是OSError的一個子類,HTTPError是URLError的一個子類,服務器上HTTP的響應會返回一個狀態碼,根據這個HTTP狀態碼,我們可以知道我們的訪問是否成功。以下範例來說明使用的方式:
URLError 類別
範例 pythonUrllib-12.py : 使用錯誤網址與正確網址來觀察 URLError 類別的回應。
# pythonUrllib-12.py from urllib import request, error headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64)\ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101\ Safari/537.36', } # 錯誤網址 url_error = 'http://aaa.24t.com.tw/' # 錯誤網址 try: htmlfile = request.urlopen(url_error) except error.URLError as e: print('錯誤原因 : ', e.reason) else: print("擷取網路資料成功") # 正確網址 url = 'http://aaa.24ht.com.tw/' # 網址正確 try: req = request.Request(url, headers=headers) htmlfile = request.urlopen(req) except error.URLError as e: print('錯誤原因 : ', e.reason) else: print("擷取網路資料成功")
執行結果
錯誤原因 : [Errno 11001] getaddrinfo failed
擷取網路資料成功
HTTPError 類別
範例 pythonUrllib-13.py : 延續 範例 pythonUrllib-12.py 觀察 URLError 和 HTTPError 類別的回應。
# pythonUrllib-13.py from urllib import request, error headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64)\ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101\ Safari/537.36', } # 錯誤1 url_error = 'http://aaa.24t.com.tw/' # 錯誤網址 try: htmlfile = request.urlopen(url_error) except error.HTTPError as e: print('錯誤代碼 : ', e.code) print('錯誤原因 : ', e.reason) print('回應表頭 : ', e.headers) except error.URLError as e: print('錯誤原因 : ', e.reason) else: print("擷取網路資料成功") print('-'*70) # 錯誤2 url = 'http://aaa.24ht.com.tw/' # 網址正確 try: htmlfile = request.urlopen(url) except error.HTTPError as e: print('錯誤代碼 : ', e.code) print('錯誤原因 : ', e.reason) print('回應表頭 : ', e.headers) except error.URLError as e: print('錯誤原因 : ', e.reason) else: print("擷取網路資料成功") print('-'*70) # 正確 url = 'http://aaa.24ht.com.tw/' # 網址正確 try: req = request.Request(url, headers=headers) htmlfile = request.urlopen(req) except error.HTTPError as e: print('錯誤代碼 : ', e.code) print('錯誤原因 : ', e.reason) print('回應表頭 : ', e.headers) except error.URLError as e: print('錯誤原因 : ', e.reason) else: print("擷取網路資料成功")
執行結果
錯誤原因 : [Errno 11001] getaddrinfo failed ---------------------------------------------------------------------- 錯誤代碼 : 406 錯誤原因 : Not Acceptable 回應表頭 : Date: Mon, 04 Oct 2021 04:47:50 GMT Server: Apache Accept-Ranges: bytes Connection: close Transfer-Encoding: chunked Content-Type: text/html ---------------------------------------------------------------------- 擷取網路資料成功
urllib.robotparser 用於解析 robots.txt 文件
urllib.robotparser 主要就是讀取網站的 robots.txt,詳細說明,請參考 : 認識 robots.txt
範例 pythonUrllib-14.py : urllib.robotparser 使用範例。
# pythonUrllib-14.py import urllib.robotparser rp = urllib.robotparser.RobotFileParser() rp.set_url("http://www.musi-cal.com/robots.txt") rp.read() print(rp.can_fetch("*", "http://www.musi-cal.com/cgi-bin/search?city=San+Francisco")) print(rp.can_fetch("*", "http://www.musi-cal.com/"))
執行結果
True
True
參考資料
特色、摘要,Feature、Summary:
關鍵字、標籤,Keyword、Tag:
- Web-Crawler,Data-Mining,Data-Science,
留言
張貼留言
Aron阿龍,謝謝您的留言互動!