Python爬虫基本库的使用
已寫章節(jié)
第一章 網(wǎng)絡(luò)爬蟲入門
第二章 基本庫的使用
第三章 解析庫的使用
第四章 數(shù)據(jù)存儲
第五章 動態(tài)網(wǎng)頁的抓取
文章目錄
- 已寫章節(jié)
- 第二章 基本庫的使用
- 2.1 urllib庫的使用(非重點)
- 2.1.1 request模塊
- 2.1.2 error模塊
- 2.1.3 parse模塊
- 2.2 requests庫的使用(重點)
- 2.2.1. requests庫的介紹
- 2.2.2 requests庫的安裝
- 2.2.3 requests庫的使用
- 2.2.3.1 requests.get()方法
- 2.2.3.2 requests.request()方法
- 2.2.3.3 處理requests庫的異常
- 2.2.3.4 發(fā)送POST請求
- 2.2.3.5 requests庫的使用實例:TOP250電影數(shù)據(jù)、抓取二進(jìn)制數(shù)據(jù)
- 2.3 正則表達(dá)式(重點)
- 2.3.1 正則表達(dá)式的介紹
- 2.3.2 Re庫
- 2.3.2.1 Re庫的介紹
- 2.3.2.2 Re庫的使用
- 2.3.2.2.1 re.match()方法
- 2.3.2.2.2 使用分組
- 2.3.2.2.3 通用匹配和匹配操作符
- 2.3.2.2.4 貪婪與非貪婪
- 2.3.2.2.5 控制標(biāo)記
- 2.3.2.2.6 re.search()
- 2.3.2.2.7 re.findall()
- 2.3.2.2.8 re.sub()
- 2.3.2.2.9 re.compile()
- 2.3.3 使用Re來爬取tx視頻
第二章 基本庫的使用
2.1 urllib庫的使用(非重點)
urllib的官方文檔
urllib是Python中自帶的HTTP請求庫,也就是說不用額外安裝就可以使用,它包含如下四個模塊:
- requests:基本的HTTP請求模塊,可以模擬發(fā)送請求
- error:異常處理模塊
- parse:一個工具模塊,提供了許多URL處理方法,比如拆分、解析、合并等。
- robotparser:它主要用來識別網(wǎng)站的robots.txt文件,讓后判斷哪些內(nèi)容可以爬取,哪些不能爬取,用得比較少。
2.1.1 request模塊
- 發(fā)送請求
使用request.urlopen()來向百度首頁發(fā)起請求,返回的是http.client.HTTPResponse對象,這個對象主要包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、version、status、reason、debuglevel、closed等屬性。將返回的HTML代碼以utf-8的編碼方式讀取并打印出來。上面的代碼執(zhí)行后將返回百度的主頁的HTML代碼。
我運行的效果如下:
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><meta name="description" content="全球最大的中文搜索引擎、致力于讓網(wǎng)民更便捷地獲取 信息,找到所求。百度超過千億的中文網(wǎng)頁數(shù)據(jù)庫,可以瞬間找到相關(guān)的搜索結(jié)果。"> 后面省略無數(shù)字......接下來再看這個例子:
# 2.2 使用urllib中的request模塊發(fā)起一個請求并獲取response對象中的信息的例子 import urllib.requestresponse = urllib.request.urlopen("http://www.python.org") print(response.read().decode('utf-8')[:100]) # 截取返回的html代碼的前100個字符的信息 print("response的類型為:" + str(type(response))) print("response的狀態(tài)為:" + str(response.status)) print("response的響應(yīng)的頭信息:" + str(response.getheaders())) print("response的響應(yīng)頭中的Server值為:" + str(response.getheader('Server')))上面的代碼使用urlopen()方法向指定的鏈接發(fā)起了一個請求,得到一個HTTPResponse對象,然后調(diào)用HTTPResponse的方法和屬性來獲取請求的狀態(tài)、請求頭信息等
下面是我的執(zhí)行結(jié)果:
<!doctype html> <!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]--> <!- response的類型為:<class 'http.client.HTTPResponse'> response的狀態(tài)為:200 response的響應(yīng)的頭信息:[('Connection', 'close'), ('Content-Length', '50890'), ('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'DENY'), ('Via', '1.1 vegur, 1.1 varnish, 1.1 varnish'), ('Accept-Ranges', 'bytes'), ('Date', 'Mon, 17 May 2021 08:59:57 GMT'), ('Age', '1660'), ('X-Served-By', 'cache-bwi5163-BWI, cache-hkg17920-HKG'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '1, 3886'), ('X-Timer', 'S1621241997.260514,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')] response的響應(yīng)頭中的Server值為:nginx- data參數(shù)
data參數(shù)是可選的,該參數(shù)是bytes類型,需要使用bytes()方法將字典轉(zhuǎn)化為字節(jié)類型,并且,該參數(shù)只能在POST請求中使用。
# 2.3 data參數(shù)的使用 import urllib.request# 使用urllib中的parse模塊中的urlencode方法來將字典轉(zhuǎn)化為字節(jié)類型,編碼方式為utf-8 data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8') response = urllib.request.urlopen('http://httpbin.org/post', data=data) print(response.read())這次我們請求的是http://httpbin.org/post這個網(wǎng)址,這個網(wǎng)址可以提供http請求測試,它可以返回請求的一些信息,其中包括我們傳遞的data參數(shù)。
- timeout參數(shù)
timeout參數(shù)用來設(shè)置超時時間,單位為秒,意思是如果請求超出了設(shè)置的這個時間,還沒有得到響應(yīng),就會拋出異常。
# 2.4 timeout參數(shù)的使用 import urllib.requestresponse = urllib.request.urlopen('http://www.baidu.com', timeout=1) print(response.read())運行結(jié)果就不展示了。
- 其他參數(shù)
除了data參數(shù)和timeout參數(shù)外,還有context參數(shù),它必須是ssl.SSLContext類型,用來指定SSL設(shè)置
Request類
urlopen()可以實現(xiàn)基本的請求的發(fā)起,但這不能構(gòu)造一個完整的請求,如果要在請求中加入Headers等信息,就可以利用更強大的Request類來構(gòu)建。
# 2.5 Request類的使用 import urllib.requestrequest = urllib.request.Request('https://python.org') print(type(request)) response = urllib.request.urlopen(request) # 傳入的是Request對象 print(response.read().decode('utf-8'))request的構(gòu)造方法:
Requests(url, data, headers, origin_host, unverifiablem, method)
- url:請求的url鏈接
- data:必須為字節(jié)流(bytes)類型
- headers:請求頭信息
- origin_req_host:請求方的host名稱或者IP地址
- unverifiable:表示這個請求是否是無法驗證的,默認(rèn)為False。
- method:指示請求使用的方法,比如:GET、POST、PUT等
下面是例子:
# 2.6 Request類的使用 from urllib import request, parseurl = "http://httpbin.org/get" headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)','Host': 'httpbin.org' } dict = {'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, headers=headers, method='GET') response = request.urlopen(req) print(response.read().decode('utf-8'))我們依然請求的是測試網(wǎng)址http://httpbin.org/get,它會返回我們發(fā)起的請求信息,下面是我的運行結(jié)果:
{"args": {}, "headers": {"Accept-Encoding": "identity", "Content-Length": "11", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)", "X-Amzn-Trace-Id": "Root=1-60a236ed-01f68c862b09c8934983ae80"}, "origin": "221.176.140.213", "url": "http://httpbin.org/get" }從結(jié)果中,我們可以看到我們發(fā)起的請求中包含了我們自己設(shè)置的User-Agent,Host和我們請求中包含的數(shù)據(jù) ‘name’: ‘Germey’。
2.1.2 error模塊
urllib中的error模塊定義了由request模塊產(chǎn)生的異常,如果出現(xiàn)了問題,request模塊就會拋出error模塊中的異常。
下面介紹其中用得比較多的兩個異常:URLError和HTTPError。
-
URLError
URLError類是error異常模塊的基類,由request模塊產(chǎn)生的異常都可以通過捕獲這個異常來處理。
# 2.7 URLError的使用例子 from urllib import request, error# 打開一個不存在的網(wǎng)頁 try:response = request.urlopen('https://casdfasf.com/index.htm') except error.URLError as e:print(e.reason)運行結(jié)果:
[Errno 11001] getaddrinfo failed
-
HTTPError
它是URLError的子類,專門用來處理HTTP請求錯誤,比如認(rèn)證請求失敗等。它有如下3個屬性:
- code:返回HTTP狀態(tài)碼
- reason:返回錯誤的原因
- headers:返回請求頭 # 2.8 HTTPError對象的屬性 from urllib import request, errortry:response = request.urlopen('https://cuiqingcai.com/index.htm') except error.HTTPError as e:print(e.reason, e.code, e.headers, sep='\n')
運行結(jié)果:
Not Found 404 Server: GitHub.com Date: Tue, 16 Feb 2021 03:01:45 GMT Content-Type: text/html; charset=utf-8 X-NWS-UUID-VERIFY: 8e28a376520626e0b40a8367b1c3ef01 Access-Control-Allow-Origin: * ETag: "6026a4f6-c62c" x-proxy-cache: MISS X-GitHub-Request-Id: 0D4A:288A:10EE94:125FAD:602B33C2 Accept-Ranges: bytes Age: 471 Via: 1.1 varnish X-Served-By: cache-tyo11941-TYO X-Cache: HIT X-Cache-Hits: 0 X-Timer: S1613444506.169026,VS0,VE0 Vary: Accept-Encoding X-Fastly-Request-ID: 9799b7e3df8bdc203561b19afc32bb5803c1f03c X-Daa-Tunnel: hop_count=2 X-Cache-Lookup: Hit From Upstream X-Cache-Lookup: Hit From Inner Cluster Content-Length: 50732 X-NWS-LOG-UUID: 5426589989384885430 Connection: close X-Cache-Lookup: Cache Miss2.1.3 parse模塊
parse模塊是用來處理url的模塊,它可以實現(xiàn)對url各部分的抽取、合并以及連接裝換等。
下面介紹parse模塊中常用的幾個方法:
-
urlparse()
實現(xiàn)url的識別和分段
# 2.9 urllib庫中parse模塊中urlparse()方法的使用 from urllib.parse import urlparseresult = urlparse('http://www.biadu.com/index.html;user?id=5#comment') print(type(result), result)result1 = urlparse('www.biadu.com/index.html;user?id=5#comment', scheme='https') print(type(result1), result1)result2 = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False) print(type(result2), result2)result3 = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False) print(result3.scheme, result3[0], result3.netloc, result3[1], sep="\n")運行結(jié)果:
<class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.biadu.com', path='/index.html', params='user', query='id=5', fragment='comment') <class 'urllib.parse.ParseResult'> ParseResult(scheme='https', netloc='', path='www.biadu.com/index.html', params='user', query='id=5', fragment='comment') <class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='') http http www.baidu.com www.baidu.com可以看到,urlparse()方法將url解析為6部分,返回的是一個ParseResult對象,這6部分是:
- scheme:😕/前面的部分,指協(xié)議
- netloc:第一個/的前面部分,指域名
- path:第一個/后面的部分,指訪問路徑
- params:;后面的部分,指參數(shù)
- query:問號后面的內(nèi)容,指查詢條件
- fragment:#號后面的內(nèi)容,值錨點
所以,可以得出一個標(biāo)準(zhǔn)的鏈接格式:
scheme://netloc/path;params?query#fragment
一個標(biāo)準(zhǔn)的URL都會符合這個規(guī)則,我們就可以使用urlparse()這個方法來將它拆分開來。
urlparse()方法還包含三個參數(shù):
urlstring:必選項,即待解析的URL
scheme:默認(rèn)協(xié)議,假如這個鏈接沒有帶協(xié)議信息,會將這個作為默認(rèn)的協(xié)議。
allow_fragments:即是否忽略fragment。如果它被設(shè)置為false,fragment就會被忽略,它會被解析為path、params或者query的一部分,而fragment部分為空
-
urlunparse()
它和urlparse()方法相反,它接收的參數(shù)是一個可迭代對象(常見的有列表、數(shù)組、集合),它的長度必須為6。
# 2.10 parse模塊中的urlparse方法的使用 from urllib.parse import urlunparsedata = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment'] print(urlunparse(data))上面的例子中傳入的是一個包含6個元素的列表,當(dāng)然可以是其他類型,如元組,只需要這個可迭代對象的長度為6個就可以了。
-
urlsplit()
和urlparse()方法相似,只不過它不再單獨解析params這一部分,而將params加入到path中,只返回5個結(jié)果
# 2.11 parse模塊中的urlsplit方法的使用 from urllib.parse import urlsplitresult = urlsplit('http://www.baidu.com/index.html;user?id=5#comment') print(result)運行結(jié)果:
SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')
-
urlunsplit()
和urlsplit()方法相反,傳入的參數(shù)也是一個可迭代的對象,例如列表、元組等,長度必須為5。
# 2.12 parse模塊中的urlunsplit方法的使用 from urllib.parse import urlunsplitdata = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment'] print(urlunsplit(data))運行結(jié)果:
http://www.baidu.com/index.html?a=6#comment
-
urljoin()
該方法接收兩個參數(shù),一個是base_url,另外一個是新的url,該方法會分析新url中的scheme、netloc、path三部分的內(nèi)容是否存在,如果某個不存在,就用base_url中的來替換。
-
urlencode()
將字典類型轉(zhuǎn)換為url中的參數(shù)
# 2.13 parse模塊中的urlencode方法的使用 from urllib.parse import urlencode params = {'name': 'germey','age': '22' } base_url = 'http://www.baidu.com?' url = base_url + urlencode(params) print(url)運行結(jié)果:
http://www.baidu.com?name=germey&age=22
-
parse_qs()、parse_qsl()
parse_qs:反序列化,將get請求參數(shù)轉(zhuǎn)化為字典
parse_qsl:反序列化,將get參數(shù)轉(zhuǎn)化為元組組成的字典
# 2.14 parse模塊中parse_qs和parse_qsl方法的使用 from urllib.parse import parse_qs, parse_qsl# 反序列化,將參數(shù)轉(zhuǎn)化為字典類型 query = 'name=germey&age=22' print(parse_qs(query))# 反序列化,將參數(shù)轉(zhuǎn)化為元組組成的列表 print(parse_qsl(query))運行結(jié)果:
{'name': ['germey'], 'age': ['22']} [('name', 'germey'), ('age', '22')]
-
quote()、unquote()
quote:將內(nèi)容轉(zhuǎn)化為URL編碼的格式,URL中帶有中文參數(shù)時,有可能會導(dǎo)致亂碼的問題,用這個方法就可以將中文字符轉(zhuǎn)化為URL編碼。
unquote:和quote()方法相反,將URL解碼
# 2.15 parse模塊中quote()方法和unquote()方法的使用 from urllib.parse import quote, unquotekeyword = '書包' url = 'https://www.baidu.com/?wd=' + quote(keyword) print(url)url = 'https://www.baidu.com/?wd=%E5%A3%81%E7%BA%B8' print(unquote(url))運行結(jié)果:
https://www.baidu.com/?wd=%E4%B9%A6%E5%8C%85 https://www.baidu.com/?wd=壁紙
urllib中的robotparse模塊可以實現(xiàn)robots協(xié)議的分析,用得不多,這里就不再介紹。
2.2 requests庫的使用(重點)
學(xué)習(xí)爬蟲,最基礎(chǔ)的便是模擬瀏覽器向服務(wù)器發(fā)出請求。
requests文檔
2.2.1. requests庫的介紹
利用Python現(xiàn)有的庫可以非常方便的實現(xiàn)網(wǎng)絡(luò)請求的模擬,常見的有urllib、requests等。requests模塊是Python原生的一款基于網(wǎng)絡(luò)請求的模塊,功能非常強大,效率極高。
作用:模擬瀏覽器發(fā)起請求
2.2.2 requests庫的安裝
requests庫是Python的第三方庫,需要額外安裝,在cmd中輸入以下代碼使用pip安裝:
pip install requests
2.2.3 requests庫的使用
要檢查是否已經(jīng)正確安裝requests庫,在編輯器或Python自帶的IDLE中導(dǎo)入requests庫:
import requests執(zhí)行后沒有發(fā)生錯誤就說明你已經(jīng)正確安裝了requests庫。
也可以在cmd命令行窗口中輸入:
pip list
后按回車,就會顯示所有pip已安裝的第三方庫,在列表中看到request庫就表明成功安裝requests庫。
下面介紹Requests庫的7個主要方法:
| requests.request() | 構(gòu)造一個請求,支撐以下的各種基礎(chǔ)方法,不常用 |
| requests.get() | 獲取HTML網(wǎng)頁的主要方法,對應(yīng)于HTTP的GET,常用 |
| requests.head() | 獲取HTML網(wǎng)頁頭信息的方法,對應(yīng)于HTTP的 |
| requests.post() | 向HTML頁面提交POST請求的方法,對應(yīng)于HTTP的POST |
| requests.put() | 向HTM頁面提交PUT請求的方法,對應(yīng)于HTTP的PUT |
| requests.patch() | 向HTML頁面提交局部修改請求,對應(yīng)于HTTP的PATCH |
| requests.delete() | 向HTML頁面提交刪除請求,對應(yīng)于HTTP的DELETE |
2.2.3.1 requests.get()方法
requests.get(url, params=None, **kwargs)
- url : 要獲取頁面的url鏈接,必選
- params :url中的額外參數(shù),字典或字節(jié)流格式,可選
- **kwargs : 12個控制訪問的參數(shù),可選
我們在瀏覽器中輸入一個url后按下enter,其實是發(fā)起一個get請求。同樣,使用requests庫發(fā)起一個get請求,可以使用requests庫下的get()方法,requests.get()方法可以構(gòu)造一個向服務(wù)器請求資源的Request對象并返回一個包含服務(wù)器資源的Response對象。request對象和response對象是requests庫中的2個重要對象,response對象包含服務(wù)器返回的所有信息,也包含請求的request信息,下面是response對象的屬性:
| r.status_code | HTTP請求的返回狀態(tài),200表示成功,404表示失敗 |
| r.text | HTTP響應(yīng)內(nèi)容的字符串形式,即url對應(yīng)的頁面內(nèi)容 |
| r.encoding | 從HTTP header中猜測的響應(yīng)內(nèi)容編碼方式,如果header中不存在charset,則認(rèn)為編碼為ISO-8859-1,r.text根據(jù)r.encoding顯示網(wǎng)頁內(nèi)容 |
| r.apparent_encoding | 從內(nèi)容中分析出的響應(yīng)內(nèi)容的編碼方式(備用編碼方式,一般比較準(zhǔn)確) |
| r.content | HTTP響應(yīng)內(nèi)容的二進(jìn)制形式 |
下面是一個使用requests.get()方法訪問百度并打印出返回的response對象的各種屬性的例子:
import requests# 2.16 使用requests.get()方法發(fā)送一個get()請求 r = requests.get("https://www.baidu.com") print("r的狀態(tài)碼為:", r.status_code) print("r的內(nèi)容為:", r.text) print("從r的header中推測的響應(yīng)內(nèi)容的編碼方式為:", r.encoding) print("從r的內(nèi)容中分析出來的響應(yīng)內(nèi)容編碼方式為:", r.apparent_encoding) print("r內(nèi)容的二進(jìn)制形式為:", r.content)2.2.3.2 requests.request()方法
requests.request(method, url, **kwargs)
- method : 請求方式,對應(yīng)get/put/post/head/patch/delete/options7種
- url : 要獲取頁面的url鏈接
- **kwargs : 控制訪問的參數(shù),共13個
**kwargs:控制訪問的參數(shù),都為可選項:
| params | 字典或字節(jié)序列,作為參數(shù)增加到url中 |
| data | 字典、字節(jié)序列或文件對象,作為request的內(nèi)容 |
| json | JSON格式的數(shù)據(jù),作為request的內(nèi)容 |
| headers | 字典,HTTP定制頭 |
| cookies | 字典或cookieJar,Request中的cookie |
| auth | 元組,支持HTTP認(rèn)證功能 |
| files | 字典類型,傳輸文件 |
| timeout | 設(shè)置超時時間,秒為單位 |
| proxies | 字典類型,設(shè)置代理服務(wù)器,可以增加登錄認(rèn)證 |
| allow_redirects | True/False,默認(rèn)為True,重定向開關(guān) |
| stream | True/False,默認(rèn)為True,獲取內(nèi)容立即下載開關(guān) |
| verify | True/False,默認(rèn)為True,認(rèn)證SSL證書開關(guān) |
| cert | 本地SSL證書路徑 |
下面只介紹幾個常用的參數(shù)。
params:字典或字節(jié)序列,作為參數(shù)增加到url中
import requests# 2.17 請求參數(shù)params參數(shù)的使用 kv = {"key1": "value1", "key2": "value2"} r = requests.request('GET', 'http://httpbin.org/get', params=kv) # 也可寫成: r = requests.get('http://httpbin.org/get', params=kv) print(r.url) print(r.text)如果向網(wǎng)站http://httpbin.org/get發(fā)起一個get請求,該網(wǎng)站會將你的請求頭的信息返回回來。
print(r.url)將輸出:
http://httpbin.org/get?key1=value1&key2=value2,
可以看到,已經(jīng)將字典作為參數(shù)增加到url中了!
同時上面的代碼print(r.text)也將請求放回的信息也打印出來了:
{
“args”: {
“key1”: “value1”,
“key2”: “value2”
},
“headers”: {
“Accept”: “/”,
“Accept-Encoding”: “gzip, deflate”,
“Host”: “httpbin.org”,
“User-Agent”: “python-requests/2.24.0”,
“X-Amzn-Trace-Id”: “Root=1-600f8cf4-6af557655f1c1a771135e7fb”
},
“origin”: “117.150.137.110”,
“url”: “http://httpbin.org/get?key1=value1&key2=value2”
}
上面就是我們發(fā)起的請求的相關(guān)信息,有請求頭、發(fā)起請求的瀏覽器、參數(shù)等。
data:字典、字節(jié)序列或文件對象,作為request的內(nèi)容
import requests# 2.18 請求參數(shù)data的使用 data = 'data' r = requests.request('POST', 'http://httpbin.org/post', data=data) # 也可寫成: r = requests.post('http://httpbin.org/post', data=data) # 這發(fā)起的是POST請求,可以看3.4 print(r.text)我執(zhí)行后的結(jié)果:
{
“args”: {},
“data”: “data”,
“files”: {},
“form”: {},
“headers”: {
“Accept”: “/”,
“Accept-Encoding”: “gzip, deflate”,
“Content-Length”: “4”,
“Host”: “httpbin.org”,
“User-Agent”: “python-requests/2.24.0”,
“X-Amzn-Trace-Id”: “Root=1-600f8f3d-46564aa85b91258f2d1c7511”
},
“json”: null,
“origin”: “117.150.137.110”,
“url”: “http://httpbin.org/post”
}
可以看到,"data"已經(jīng)作為request的內(nèi)容了。
json:JSON格式的數(shù)據(jù),作為request的內(nèi)容
import requests# 2.19 請求參數(shù)json的使用 kv = {'key1':'value1'} r = requests.request('POST', 'http://httpbin.org/post', json=kv) # 也可寫成:r = requests.post('http://httpbin.org/post', json=kv) print(r.text)我執(zhí)行后的結(jié)果:
{
“args”: {},
“data”: “{“key1”: “value1”}”,
“files”: {},
“form”: {},
“headers”: {
“Accept”: “/”,
“Accept-Encoding”: “gzip, deflate”,
“Content-Length”: “18”,
“Content-Type”: “application/json”,
“Host”: “httpbin.org”,
“User-Agent”: “python-requests/2.24.0”,
“X-Amzn-Trace-Id”: “Root=1-600f8f00-2419855b4f772b4851c12cdd”
},
“json”: {
“key1”: “value1”
},
“origin”: “117.150.137.110”,
“url”: “http://httpbin.org/post”
}
headers:字典、HTTP定制頭
請求頭Headers提供了關(guān)于請求、響應(yīng)或其他發(fā)送實體的信息。對于爬蟲而言,請求頭非常重要,有很多網(wǎng)站會通過檢查請求頭來判斷請求是不是爬蟲發(fā)起的。
那如何找到正確的Headers呢?
在Chrome中或其他瀏覽器打開要請求的網(wǎng)頁,右擊網(wǎng)頁任意處,在彈出的菜單中單擊“檢查"選項,
點擊Network,點擊下面的資源列表中的任意一個,我點擊的是第一個,在右邊彈出的界面中找到Requests Headers,就可以看到Requests Headers中的詳細(xì)信息:
我們將Requests Headers中的user-agent對應(yīng)的信息復(fù)制下來,用在下面的代碼中:
我的運行結(jié)果:
{
“args”: {},
“data”: “”,
“files”: {},
“form”: {},
“headers”: {
“Accept”: “/”,
“Accept-Encoding”: “gzip, deflate”,
“Content-Length”: “0”,
“Host”: “httpbin.org”,
“User-Agent”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36”,
“X-Amzn-Trace-Id”: “Root=1-600f9f2f-016953bc4635251a20212054”
},
“json”: null,
“origin”: “117.150.137.110”,
“url”: “http://httpbin.org/post”
}
可以看到,我們的請求頭中的user-Agent已經(jīng)變成我們自己構(gòu)造的了!
timeout:設(shè)置超時時間,秒為單位
import requests# 2.21 請求參數(shù)timeout的使用 r = requests.request('GET', 'http://www.baidu.com', timeout=10) # 也可寫成: r = requests.request('http://www.baidu.com', timeout=10)proxies:字典類型,設(shè)定訪問代理服務(wù)器,可以增加代理驗證
import requests# 2.22 請求參數(shù)proxies的使用 pxs = {'http': 'http://user:pass@10.11.1:12344''https': 'https://10.10.10.1.12344' } r = requests.request('GET', 'http://www.baidu.com', proxies=pxs) # 也可寫成: r = requests.get('http://www.baidu.com', proxies=pxs)cookies: 字典或cookieJar,Request中的cookie
首先看一下獲取cookie的過程:
import requests# 2.23 請求參數(shù)cookies的使用 r = requests.request('GET', 'https://www.baidu.com') # 也可寫成: r = requests.get('https://www.baidu.com') print(r.cookies)for key, value in r.cookies.items():print(key + '=' + value)運行結(jié)果如下:
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ=27315
第一行是直接打印的cookie信息,我們發(fā)現(xiàn)它是RequestCookieJar類型。第二行是遍歷的Cookie的信息。
我們也可以使用Cookie來保持登錄狀態(tài),以登錄百度為例,首先,登錄百度,讓后用上面我教你的方法來獲取Requests Headers中的user-agent和cookie的信息,將它們設(shè)置到Headers中,然后發(fā)送請求:
import requests# 2.24 使用cookies的實例 headers = {'Cookie': 'BIDUPSID=A41FB9F583DE46FF509B8F9443183F5C;\PSTM=1604237803; BAIDUID=A41FB9F583DE46FF6179FBA5503669E3:FG=1;\BDUSS=jdRb3ZMQTR5OX5XYTd1c0J3eUVSWGVlRVgxZ0VlMjRFR3dGMkZZMDlMNWR\3eWRnRVFBQUFBJCQAAAAAABAAAAEAAACzkIz7vfDP~rarMzIxAAAAAAAAAAAAAAAAAA\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF02AGBdNgBgW;\BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=33425_33437_33344_\31253_33284_33398_33459_26350; delPer=0; PSINO=3; BD_HOME=1; BD_UPN=123\14753; BA_HECTOR=2k808k8h0000a18g001g0v9e80r','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, \like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.50' } r = requests.request('GET', "https://www.baidu.com", headers=headers) # 也可以寫成 r = requests.get("https://www.baidu.com", headers=headers) print(r.text)這樣,我們就實現(xiàn)了用Python模擬登錄到百度了,結(jié)果中包含我們只有登錄百度后才能查看的信息。
2.2.3.3 處理requests庫的異常
在上面的代碼中,r=requests.get(“https://www.baidu.com”),并不是在任何時候都會成功,如果鏈接打錯或訪問的鏈接不存在,則會產(chǎn)生異常。下面列出了常見的異常:
| requests.ConnectionError | 網(wǎng)絡(luò)鏈接錯誤,入DNS查詢失敗,拒絕鏈接等 |
| requests.HTTPError | HTTP錯誤異常 |
| requests.URLRequired | URL缺失異常 |
| requests.TooManyRedirects | 超過最大重定向次數(shù),產(chǎn)生重定向異常 |
| requests.ConnectionTimeout | 鏈接遠(yuǎn)程服務(wù)器超時異常 |
| requests.Timeout | 請求URL超時,產(chǎn)生超時異常 |
處理異常,可以使用requests.raise_for_status()方法,該方法在其內(nèi)部判斷r.status_code是否等于200,不需要增加額外的if語句:
import requests# 2.25 處理發(fā)送請求過程中的異常 try:# 下面的鏈接錯了,將打印輸出"參數(shù)異常"r = requests.get("https://www.baidu.co")r.raise_for_status()r.encoding = r.apparent_encodingprint(r.text) except:print("產(chǎn)生異常")2.2.3.4 發(fā)送POST請求
除了GET請求外,有時還需要發(fā)送一些編碼為表單形式的數(shù)據(jù),如在登錄的時候請求就為POST,因為如果使用GET請求,密碼就會顯示在URL中,這是非常不安全的。如果要實現(xiàn)POST請求,其實在上面的介紹requests.request( )方法時就已經(jīng)實現(xiàn)了,你也可以看看下面用requests.post()方法實現(xiàn)的代碼,對比后發(fā)現(xiàn),requests.post()方法其實就是將requests.request(‘POST’, …)方法給包裝起來了,這也是為什么說requests.request()方法是實現(xiàn)其他方法的基礎(chǔ)了,上面的例子中也建議大家不用requests.request()方法。
import requests# 2.26 發(fā)送POST請求 key_dict = {'key1':'value1', 'key2': 'value2'} r = requests.post('http://httpbin.org/post', data=key_dict) # 也可寫成: r = requests.request('POST', 'http://httpbin.org/post', data=key_dict) print(r.text)按照上面的requests.request()方法的13個訪問參數(shù),你就會將其應(yīng)用到requests.get()或requests.post()方法中了吧!在來看一個例子:
import requestsr = requests.get('http://www.baidu.con', timeout=3) print(r.text)2.2.3.5 requests庫的使用實例:TOP250電影數(shù)據(jù)、抓取二進(jìn)制數(shù)據(jù)
打開豆瓣電影TOP250的網(wǎng)站,右鍵鼠標(biāo),使用“檢查"功能查看該網(wǎng)頁的請求頭:
按照下面提取請求頭中的重要信息:
使用這個headers構(gòu)造請求頭并爬取前25個電影的名稱,提取部分的代碼大家看不懂沒關(guān)系,大家只要看懂請求發(fā)起代碼的實現(xiàn):
import requests from bs4 import BeautifulSoup# 2.27 發(fā)送get請求爬取豆瓣電影的前25個電影 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.50','Host': 'movie.douban.com' } r = requests.get('https://movie.douban.com/top250', headers=headers, timeout=10) try:r.raise_for_status()soup = BeautifulSoup(r.text, 'html.parser')movies = soup.find_all('div', {'class': 'hd'})for each in movies:print(each.a.span.text.strip()) except:print("error")執(zhí)行后將輸出:
肖申克的救贖
霸王別姬
阿甘正傳
這個殺手不太冷
…
下面是一個抓取favicon.ico圖標(biāo)的例子:
import requests# 2.28 發(fā)送get請求爬取圖片 r = requests.get('https://github.com/favicon.ico') with open('favicon.ico', 'wb') as f:f.write(r.content)運行結(jié)束后,文件夾中將出現(xiàn)名為favicon.ico的圖標(biāo)。上面的代碼先使用get方法發(fā)起一個get請求,讓后將請求返回的內(nèi)容以wb(二進(jìn)制)寫入favicon.ico文件中。
2.3 正則表達(dá)式(重點)
2.3.1 正則表達(dá)式的介紹
本節(jié)中,我們看一下正則表達(dá)式的相關(guān)用法。正則表達(dá)式是處理字符串的強大工具,它有自己特定的語法結(jié)構(gòu),有了它,實現(xiàn)字符串的檢索、替換、匹配驗證都不在話下。
正則表達(dá)式是用來簡介表達(dá)一組字符串的表達(dá)式,正則表達(dá)式是一種通用的字符串表達(dá)框架。正則表達(dá)式可以用來判斷某字符串的特征歸屬。
在爬蟲中,我們使用它來從HTML中提取想要的信息就非常方便了。
例如:正則表達(dá)式:
p(Y|YT|YTH|YTHO)?N
它可以表示:
- ‘PN’
- ‘PYN’
- ‘PYTN’
- ‘PYTHN’
- ‘PYTHON’
這5個字符串。
正則表達(dá)式語法由字符和操作符構(gòu)成,上面的例子中的() | ? 都是操作符,其他的是字符。
下面是正則表達(dá)式的常用的操作符:
| . | 表示任何單個字符,除了換行符 | |
| [ ] | 字符集,對單個字符給出取值范圍 | [abc]表示a、b、c,[a-z]表示a到z單個字符 |
| [^ ] | 非字符集,對單個字符給出排除范圍 | [^abc]表示非a非b非c的單個字符 |
| * | 前一個字符0次或無限次擴展 | abc*表示ab、abc、abcc、abccc等 |
| + | 前一個字符1次或無限次擴展 | abc+表示abc、abcc、abccc等 |
| ? | 前一個字符0次或1次擴展 | abc?表示ab、abc |
| | | 左右表達(dá)式中任意一個 | abc|def表示abc、def |
| {m} | 擴展前一個字符m次 | ab{2}c表示abbc |
| {m, n} | 擴展前一個字符m至n次(含n) | ab{1,2}c表示abc、abbc |
| ^ | 匹配字符串開頭 | ^abc表示abc且在一個字符串的開頭 |
| $ | 匹配字符串結(jié)尾 | abc$表示abc且在一個字符的結(jié)尾 |
| ( ) | 分組標(biāo)記,內(nèi)部只能使用|操作符 | (abc)表示abc,(abc|def)表示abc、def |
| \d | 數(shù)字,等價于[0-9] | |
| \D | 匹配非數(shù)字 | |
| \w | 匹配非特殊字符,即a-z、A-Z、0-9、_、漢字 | |
| \W | 匹配特殊字符,即非字母、非數(shù)字、非漢字、非_ | |
| \n | 匹配一個換行符 | |
| \s | 匹配空白 | |
| \S | 匹配非空白 |
正則表達(dá)式語法實例:
| p(Y|YT|YTH|YTHO)?N | ‘PN’,‘PYN’,‘PYTN’,‘PYTHN’,‘PYTHON’ |
| PYTHON+ | ‘PYTHON’,‘PYTHONN’,‘PYTHONNN’ … |
| PY[TH]ON | ‘PYTON’,‘PYHON’ |
| PY[^TH]?ON | ‘PYON’,‘PYaON’,‘PYbON’,‘PYcON’ … |
| PY{ : 3}N | ‘PN’,‘PYN’,‘PYYN’、‘PYYYN’ |
經(jīng)典正則表達(dá)式實例:
| ^[A-Za-z]+$ | 由26個字母組成的字符串 |
| ^[A-Za-z0-9]+$ | 由26個字母和數(shù)字組成的字符串 |
| ^\d+$ | 整數(shù)形式的字符串 |
| ^[0-9]*[1-9][0-9]*$ | 正整數(shù)形式的字符串 |
| [1-9]\d{5} | 中國境內(nèi)的郵政編碼,6位 |
| [\u4e00-\u9fa5] | 匹配中文字符 |
| \d{3}-\d{8}|\d{4}-\d{7} | 國內(nèi)電話號碼,010-68913536 |
| \d+.\d+.\d+.\d+. 或 \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3} | 匹配IP地址的字符串 |
其實正則表達(dá)式不是Python僅有的,它也出現(xiàn)在其他的編程語言中,只不過語法可能有一點不同。Python中的re庫提供了整個正則表達(dá)式的實現(xiàn),下面就來介紹re庫。
2.3.2 Re庫
2.3.2.1 Re庫的介紹
Re庫是Python的標(biāo)準(zhǔn)庫,主要用于字符串匹配。
re文檔
python中的re庫文檔
2.3.2.2 Re庫的使用
要使用Re庫,必須先安裝re庫:
pip install re
re庫的主要功能函數(shù):
| re.match() | 從一個字符串的開始位置起匹配正則表達(dá)式 |
| re.search() | 在一個字符串中搜索匹配正則表達(dá)式的第一個位置 |
| re.findall() | 搜索字符串,以列表類型返回全部能匹配的字符串 |
| re.sub() | 在一個字符串中替換所有匹配正則表達(dá)式的子串,返回替換后的字符串 |
2.3.2.2.1 re.match()方法
re.match(pattern, string, flags=0)
- pattern:正則表達(dá)式(可以是字符串或原生字符串)
- string:待匹配字符串
- flags:正則表達(dá)式使用時的控制標(biāo)記(可選)
? 常見的控制標(biāo)記:
| re.I re.IGNORECASE | 忽略正則表達(dá)式的大小寫,[A-Z]能夠匹配小寫字符 |
| re.M re.MULTILTNE | 正則表達(dá)式中的^操作符能夠?qū)⒔o定字符串的每一行當(dāng)做匹配開始 |
| re.S re.DOTALL | 正則表達(dá)式中的.操作符能夠匹配所有的字符,默認(rèn)匹配除換行符以外的所有字符 |
match()方法會嘗試從字符串的起始位置匹配正則表達(dá)式,如果匹配,就返回匹配成功的結(jié)果,否則,返回None:
import re# 2.29 re.match()方法的使用 content = 'dfs 234 d 3 34' result = re.match('..', content) print(type(result)) print(result) print(result.group()) print(result.span())下面是執(zhí)行結(jié)果:
<class 're.Match'> <re.Match object; span=(0, 2), match='df'> df (0, 2)從結(jié)果可以看出,re.match()方法返回一個re.Match對象,該對象有兩種常用的方法:
- group():匹配結(jié)果的內(nèi)容,如果有分組,則分組是從1開始的,group[1]表示第一個分組,group[2]表示第二個分組,以此類推。
- span():輸出匹配到的字符串在原字符串中的起始位置,上面的(0,2)中的0和2就代表了df在’dfs 234 d 3 34’中的起始位置。
正則表達(dá)式…匹配到的字符串是df。
2.3.2.2.2 使用分組
上面的例子中,我們用match()方法匹配到了我們想要的字符串,但是,如果我們想要的字符串在匹配結(jié)果中該怎么辦?
例如:
# 2.30 使用分組() import recontent = 'a1234567atsea' result = re.match('a\d{7}a', content) print(result) print(result.group()) print(result.span())我們要在content中將數(shù)字提取出來,我們發(fā)現(xiàn)數(shù)字都包含在a這個字母中間,所以用a\\d{7}a這個正則表達(dá)式來提取,\d表示任意一個數(shù)字,再用{7}將\d(任意一個數(shù)字)匹配7個,運行結(jié)果如下:
a1234567a (0, 9)我么發(fā)現(xiàn)匹配結(jié)果中開頭和結(jié)尾都包含了一個a,如何只得到1234567能,我們只需要使用分組,并將上面的代碼修改一下就行了:
import re# 2.31 分組()的使用 content = 'a1234567atsea' result = re.match('a(\d{7})a', content) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
a1234567a (0, 9) 1234567將正則表達(dá)式中的\d{7}的兩邊加上小括號,將其作為一個分組,在匹配結(jié)果中使用group(1)將分組取出,可以看到,我們想要的1234567就在匹配結(jié)果中的第一個分組中了(group(1))。
2.3.2.2.3 通用匹配和匹配操作符
在使用正則表達(dá)式的時候,要熟練使用.*(通用匹配),其中,.可以匹配任意一個字符,*(星)代表匹配前面的字符無限次,所以它們組合在一起就可以匹配任意字符了(換行符除外)。
下面來看一個通用匹配(.*)的例子:
import re# 2.32 通用匹配(.*)的使用 content = 'rtgfga1234567atsea' result = re.match('.*(\d{7}).*', content) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
rtgfga1234567atsea (0, 18) 1234567上面的例子中,我們使用了.*來匹配數(shù)字前的任意字符串和數(shù)字之后的任意字符串,在使用分組獲得 我們想要的數(shù)字。
有時候,我們要匹配的字符中包括操作符該怎么辦?可以使用\來將操作符轉(zhuǎn)義,請看下面的例子:
import re# 2.33 在正則表達(dá)式中使用轉(zhuǎn)義符 content = '12df www.baidu.com df' result = re.match('12df\s(www\.baidu\.com)\sdf', content) print(result.group()) print(result.span()) print(result.group(1))在content中,我們要提取www.baidu.com,其中的.是操作符,在寫正則表達(dá)式時,我們不能用.來匹配. 因為.代表任意一個字符,我們用\來將其轉(zhuǎn)義,就可以用\.來匹配點了。運行結(jié)果如下:
12df www.baidu.com df (0, 21) www.baidu.com2.3.2.2.4 貪婪與非貪婪
由于.*代表任意字符串,這就有一個問題,例如:
import re# 2.34 貪婪模式 content = 'dfadas1234567assedf' result = re.match('df.*(\d+).*df', content) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
dfadas1234567assedf (0, 19) 7(\d+)分組只匹配到了7這一個數(shù)字,我們想要匹配1234567,這是為什么?
這就涉及到了貪婪與非貪婪,由于.*可以匹配任意長度的字符串,所以.*就盡可能的的匹配較多的字符,于是,它就匹配了adas123456,而只讓\d+只匹配到一個7。
貪婪:讓.*匹配盡可能多的字符
非貪婪:讓.*匹配盡可能少的字符
默認(rèn).*是貪婪的,要讓.*是非貪婪的,只需要在.*的后面加上?,即:.*?
知道如何將.*設(shè)置為非貪婪模式后,我們就可以將上面的代碼改為如下的代碼:
import re# 2.35 非貪婪模式 content = 'dfadas1234567assedf' result = re.match('df.*?(\d+).*?df', content) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
dfadas1234567assedf (0, 19) 1234567這就匹配到了我們想要的1234567了。
2.3.2.2.5 控制標(biāo)記
正則表達(dá)式可以包含一些可選標(biāo)志修飾符來控制匹配的模式,常見的控制標(biāo)記大家可以看上面介紹re.match()方法中列出的控制標(biāo)記表格。
下面的代碼中,我們?nèi)稳皇翘崛∽址械乃袛?shù)字:
import recontent = 'dfadas1234567assedf' result = re.match('^df.*?(\d+).*?df$', content) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
dfadas1234567assedf (0, 19) 1234567我們成功將字符串中的所有數(shù)字提取出來了,但是,我將content修改一下:
import recontent = '''dfadas1234567assedf''' result = re.match('^df.*?(\d+).*?df$', content) print(result.group()) print(result.span()) print(result.group(1))再運行:
Traceback (most recent call last):File "E:/pycharmWorkStation/venv/Include/draft/test.py", line 6, in <module>print(result.group()) AttributeError: 'NoneType' object has no attribute 'group'Process finished with exit code 1發(fā)現(xiàn)出錯了!原因是.匹配任意一個除了換行符之外的任意字符,所以.*?匹配到換行符就不能匹配了,導(dǎo)致我們沒有匹配到任何字符,放回結(jié)果為None,而在第6行,我們調(diào)用了None的group()方法。
要修正這個錯誤,我們只需要添加一個re.S控制標(biāo)記,這個標(biāo)記的作用是使.匹配任意一個包括換行符在內(nèi)的字符。
import re# 2.36 控制標(biāo)記的使用 content = '''dfadas1234567assedf''' result = re.match('^df.*?(\d+).*?df$', content, re.S) print(result.group()) print(result.span()) print(result.group(1))運行結(jié)果如下:
dfadas1234567assedf (0, 30) 1234567這個re.S控制標(biāo)記在網(wǎng)頁匹配中經(jīng)常用到。因為HTMl節(jié)點經(jīng)常會換行,加上它,就可以匹配節(jié)點與節(jié)點中的換行了。
2.3.2.2.6 re.search()
上面講的match()方法是從字符串的開頭開始匹配的,一旦開頭就不能匹配,就會導(dǎo)致匹配的失敗,請看下面的例子:
import re# 2.37 re.match()方法是從頭開始匹配的 content = 'df colle 123' result = re.match('colle\s123', content) print(result.group()) print(result.span())運行結(jié)果出錯,沒有匹配到結(jié)果,返回的是None,None對象沒有g(shù)roup()方法。
re.search():在匹配時掃描整個字符串,讓后返回成功匹配的第一個結(jié)果,如果搜索完了還未找到匹配的,就返回None。也就是說,正則表達(dá)式可以是字符串的一部分
import re# 2.38 re.search()方法的使用 content = 'df colle 123' result = re.search('colle\s123', content) print(result.group()) print(result.span())運行結(jié)果:
colle 123 (3, 12)2.3.2.2.7 re.findall()
上面所講到的search()方法可以返回匹配到的第一個內(nèi)容,如果我們想要得到所有匹配到的結(jié)果就可以使用findall()方法。
re.findall():搜索字符串,以列表類型返回全部能匹配的子串
import re# 2.39 re.findall()方法的使用 content = 'df colle 123 colle 123' result = re.findall('colle\s123', content) print(result)運行結(jié)果:
['colle 123', 'colle 123']2.3.2.2.8 re.sub()
re.sub():將文本中所以匹配的內(nèi)容替換為指定的文本
import re# 2.40 re.sub()方法的使用 content = 'dfcolle123colle123' content = re.sub('\d', '', content) print(content)運行結(jié)果:
dfcollecolle上面的代碼中,我們將content中所有與\d(任意一個數(shù)字)匹配的結(jié)果替換為’ ',就去掉了content中所有的數(shù)字。
2.3.2.2.9 re.compile()
re.compile():將正則字符串編譯成正則表達(dá)式對象,可以用來復(fù)用。
import re# 2.41 re.compile()方法的使用 content1 = 'dfcolle123colle123' content2 = 'sdf123e' content3 = 'ss23dsfd'pattern = re.compile('\d')content1 = re.sub(pattern, '', content1) content2 = re.sub(pattern, '', content2) content3 = re.sub(pattern, '', content3) print(content1,' ',content2,' ',content3)代碼中,我們將’\d‘編譯為一個正則表達(dá)式對象,并在下面的代碼中將它復(fù)用。
運行結(jié)果:
dfcollecolle sdfe ssdsfd2.3.3 使用Re來爬取tx視頻
下面來使用re來獲取tx視頻主頁中的所有鏈接和排行榜中所有的電影名稱。
打開tx視頻的主頁,右擊,“檢查”,選擇“元素”:
隨便找到一個鏈接,例如我在圖中畫出來的,根據(jù)它寫出匹配所有連接的正則表達(dá)式:
'"((https|http)://.*?)"'
按照如下的圖示來獲取請求的URL、user-Agent、cookie
重新回到“元素”:
按照如下操作獲取排行榜中電影所在的元素:
重復(fù)上面的操作,多獲取幾個排行榜中電影名所在的元素:
例如:
<span class="rank_title">有翡</span> <span class="rank_title">我的小確幸</span> <span class="rank_title">我就是這般女子</span>根據(jù)它寫出提取排行榜電影名稱的正則表達(dá)式為:
‘<span\sclass=“rank_title”>(.*?)’
根據(jù)上面步驟得出的信息可以寫出如下代碼:
import re import requests# 2.42 使用re爬取騰訊視頻的小例子 url = "https://v.qq.com/" # 要爬取的鏈接 headers = { # 構(gòu)造請求頭'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'\' AppleWebKit/537.36 (KHTML, like Gecko) C'\'hrome/88.0.4324.96 Safari/537.36 Edg/88.0.'\'705.53','cookie': 'pgv_pvi=2265568256; pgv_pvid=1230518102; tvfe'\'_boss_uuid=19b8c4da4cc7e833; ts_uid=9797476283'\'; ts_refer=www.baidu.com/link; RK=VGQx4w/ntj; '\'ptcz=fe2dbdf4d8d7efb795bfdc0deaa0429286aa73e0dd'\'444a9173fe43fc7b145a1e; ptag=www_baidu_com; ad_pl'\'ay_index=77; pgv_info=ssid=s5748488123; ts_last=v.'\'qq.com/; bucket_id=9231006; video_guid=8b478b9f33d3db'\'89; video_platform=2; qv_als=cyHwW4MZHa8e9NWRA1161181'\'1694iJW+zw==', } proxy={ # 代理"HTTP": "113.3.152.88:8118","HTTPS":"219.234.5.128:3128", }r = requests.get(url=url, headers=headers, proxies=proxy, timeout=3) # 傳入url、headers、proxies、timeout構(gòu)造get請求 print("狀態(tài)碼為:", r.status_code) # 打印狀態(tài)碼 r.encoding = r.apparent_encoding # 將編碼方式設(shè)置為備用編碼方式pattern = re.compile('"((https|http)://.*?)"', re.S) # 使用re來獲取所有的鏈接,并打印前5個 links = re.findall(pattern, r.text) print("鏈接個數(shù)為:", len(links)) for i in range(5):print(links[i][0])pattern1 = re.compile('<span\sclass="rank_title">(.*?)</span>', re.S) # 使用re來獲取排行榜中所有的電影名稱并 movies = re.findall(pattern1, r.text)print() # 將排行榜中的所有電影名稱打印出來 for i in movies:print(i)當(dāng)然,這是我的代碼,大家可以將其中的cookie、user-agent和proxy替換為自己的。
運行結(jié)果如下:
狀態(tài)碼為: 200 鏈接個數(shù)為: 1331 http://m.v.qq.com/index.html?ptag= https://puui.qpic.cn/vupload/0/common_logo_square.png/0 http://www.w3.org/2000/svg https://v.qq.com/ https://film.qq.com/有翡 我的小確幸 我就是這般女子 暗戀橘生淮南 這個世界不看臉 山海情[原聲版] 陀槍師姐2021[普通話版] 黑白禁區(qū) 大秦賦 陳情令 長安伏妖 詭婳狐 除暴 赤狐書生 有匪·破雪斬 蜘蛛俠:平行宇宙 重案行動之搗毒任務(wù) 武動乾坤:九重符塔 昆侖神宮 絕對忠誠之國家利益 哈哈哈哈哈 王牌對王牌 第6季 歡樂喜劇人 第7季 我就是演員 第3季 平行時空遇見你 現(xiàn)在就告白 第4季 你好生活 第2季 非常完美 乘風(fēng)破浪的姐姐slay全場 天賜的聲音 第2季 斗羅大陸 開心錘錘 狐妖小紅娘 雪鷹領(lǐng)主 武神主宰 靈劍尊 豬屁登 萬界仙蹤當(dāng)然,這是我的運行結(jié)果,大家的運行結(jié)果可能和我不一樣,因為排行榜是會變化的。
總結(jié)
以上是生活随笔為你收集整理的Python爬虫基本库的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: An internal error oc
- 下一篇: 内存频率选择:不只看频率,还需考虑CPU