源:【公眾號】
Python技術(shù)
爬蟲(又稱為網(wǎng)頁蜘蛛,網(wǎng)絡(luò)機器人,在 FOAF 社區(qū)中間,更經(jīng)常的稱為網(wǎng)頁追逐者);它是一種按照一定的規(guī)則,自動地抓取網(wǎng)絡(luò)信息的程序或者腳本。
如果我們把互聯(lián)網(wǎng)比作一張大的蜘蛛網(wǎng),那一臺計算機上的數(shù)據(jù)便是蜘蛛網(wǎng)上的一個獵物,而爬蟲程序就是一只小蜘蛛,他們沿著蜘蛛網(wǎng)抓取自己想要的獵物/數(shù)據(jù)。
網(wǎng)頁的請求和響應方式是 Request 和 Response
Request:用戶將自己的信息通過瀏覽器(socket client)發(fā)送給服務(wù)器(socket server)
Response:服務(wù)器接收請求,分析用戶發(fā)來的請求信息,收到請求信息后返回數(shù)據(jù)(返回的數(shù)據(jù)中可能包含其他鏈接,如:image、js、css等)
瀏覽器在接收 Response 后,會解析其內(nèi)容來顯示給用戶,而爬蟲程序在模擬瀏覽器發(fā)送請求然后接收 Response 后,是要提取其中的有用數(shù)據(jù)。
請求的發(fā)起是使用 http 庫向目標站點發(fā)起請求,即發(fā)送一個Request
Request對象的作用是與客戶端交互,收集客戶端的 Form、Cookies、超鏈接,或者收集服務(wù)器端的環(huán)境變量。
Request 對象是從客戶端向服務(wù)器發(fā)出請求,包括用戶提交的信息以及客戶端的一些信息??蛻舳丝赏ㄟ^ HTML 表單或在網(wǎng)頁地址后面提供參數(shù)的方法提交數(shù)據(jù)。
然后服務(wù)器通過 request 對象的相關(guān)方法來獲取這些數(shù)據(jù)。request 的各種方法主要用來處理客戶端瀏覽器提交的請求中的各項參數(shù)和選項。
Request 包含:請求 URL、請求頭、請求體等
Request 請求方式: GET/POST
請求url: url全稱統(tǒng)一資源定位符,一個網(wǎng)頁文檔、一張圖片、 一個視頻等都可以用url唯一來確定
請求頭: User-agent:請求頭中如果沒有 user-agent 客戶端配置,服務(wù)端可能將你當做一個非法用戶;
cookies: cookie 用來保存登錄信息
一般做爬蟲都會加上請求頭
例如:抓取百度網(wǎng)址的數(shù)據(jù)請求信息如下:
爬蟲程序在發(fā)送請求后,如果服務(wù)器能正常響應,則會得到一個Response,即響應;
Response 信息包含:html、json、圖片、視頻等,如果沒報錯則能看到網(wǎng)頁的基本信息。例如:一個的獲取網(wǎng)頁響應內(nèi)容程序如下:
import requests
request_headers={
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Cookie': 'BIDUPSID=088AEC1E85F75590978FB3643E131FBA; PSTM=1603682377; BD_UPN=12314753; BDUSS_BFESS=s877ukkvpiduup96naoovu0b94; __yjs_duid=1_04c448abb85383e7fef98fb64b828cce1611538687284; BAIDUID=C6421D51B2DBFF82716EE84B116A4EF8:FG=1; BDSFRCVID_BFESS=rqtOJeC62uF1xmOeQXfguRnVq2hi4t5TH6aINJzxxKt_7w4IsZNSEG0PVf8g0Kubuo1BogKKWeOTHx8F_2uxOjjg8UtVJeC6EG0Ptf8g0f5; H_BDCLCKID_SF_BFESS=tbCH_ItXfCP3JRnYb-Qoq4D_MfOtetJyaR0fKU7vWJ5TEJjz3tuabp_8Lx4H3bQNaHc3Wlvctn3cShPCy-7m-p_z-J6bK6jULNchMhrL3l02VMQae-t2ynLV5HAOW-RMW23U0l7mWPPWsxA45J7cM4IseboJLfT-0bc4KKJxbnLWeIJEjjChDTcyeaLDqbQX2COXsROs2ROOKRcgq4bohjPDynn9BtQmJJrtX4Jtb4oqE4FxQRoChlKJhJAO2JJqQg-q3R5lLt02VlQueq3vBP0Fbfv80x-jLIOOVn0MW-KVo-Jz5tnJyUPibtnnBnkO3H8HL4nv2JcJbM5m3x6qLTKkQN3T-PKO5bRu_CFbtC_hMD-6j6RV-tAjqG-jJTkjt-o2WbCQ-tjM8pcNLTDK5f5L2Mc9Klov5DvtbJrC-CosjDbmjqO1j4_PX46EhnvibN8fLKbY-McFVp5jDh34b6ksD-Rt5JQytmry0hvcQb5cShn9eMjrDRLbXU6BK5vPbNcZ0l8K3l02V-bIe-t2b6Qh-p52f6LjJbC83e; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=33425_33439_33258_33272_31660_33463_33459_33321_33264; BAIDUID_BFESS=983CAD9571DCC96332320F573A4A81D5:FG=1; delPer=0; BD_CK_SAM=1; PSINO=7; BDRCVFR[tox4WRQ4-Km]=mk3SLVN4HKm; BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; BDRCVFR[CLK3Lyfkr9D]=mk3SLVN4HKm; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; BD_HOME=1; H_PS_645EC=0c49V2LWy0d6V4FbFplBYiy6xyUu88szhVpw2raoJDgdtE3AL0TxHMUUFPM; BA_HECTOR=0l05812h21248584dc1g38qhn0r; COOKIE_SESSION=1_0_8_3_3_9_0_0_7_3_0_1_5365_0_3_0_1614047800_0_1614047797%7C9%23418111_17_1611988660%7C5; BDSVRTM=1',
'Host':'www.baidu.com',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36'}
response = requests.get('https://www.baidu.com/s',params={'wd':'帥哥'},headers=request_headers) #params內(nèi)部就是調(diào)用urlencode
print(response.text)
以上內(nèi)容輸出的就是網(wǎng)頁的基本信息,它包含 html、json、圖片、視頻等,如下圖所示:
Response 響應后會返回一些響應信息,例下:
1、響應狀態(tài)
2、Respone header
3、preview 是網(wǎng)頁源代碼
4、解析內(nèi)容
解析 html 數(shù)據(jù):解析 html 數(shù)據(jù)方法有使用正則表達式、第三方解析庫如 Beautifulsoup,pyquery 等
解析 json 數(shù)據(jù):解析 json數(shù)據(jù)可使用 json 模塊
解析二進制數(shù)據(jù):以 b 的方式寫入文件
5、保存數(shù)據(jù)
爬取的數(shù)據(jù)以文件的形式保存在本地或者直接將抓取的內(nèi)容保存在數(shù)據(jù)庫中,數(shù)據(jù)庫可以是 MySQL、Mongdb、Redis、Oracle 等……
爬蟲的總流程可以理解為:蜘蛛要抓某個獵物-->沿著蛛絲找到獵物-->吃到獵物;即爬取-->解析-->存儲;
在爬取數(shù)據(jù)過程中所需參考工具如下:
今天的文章是對爬蟲的原理做一個詳解,希望對大家有幫助,同時也在后面的工作中奠定基礎(chǔ)!
源:Python之禪 作者:劉志軍
題圖:@Miguel Mateo
系列文章的第3篇介紹了網(wǎng)絡(luò)請求庫神器 Requests ,請求把數(shù)據(jù)返回來之后就要提取目標數(shù)據(jù),不同的網(wǎng)站返回的內(nèi)容通常有多種不同的格式,一種是 json 格式,這類數(shù)據(jù)對開發(fā)者來說最友好。另一種 XML 格式的,還有一種最常見格式的是 HTML 文檔,今天就來講講如何從 HTML 中提取出感興趣的數(shù)據(jù)
直接字符串處理?自己寫個 HTML 解析器來解析嗎?還是用正則表達式?這些都不是最好的辦法,好在,Python 社區(qū)在這方面早就有了很成熟的方案,BeautifulSoup 就是這一類問題的克星,它專注于 HTML 文檔操作。
BeautifulSoup 是一個用于解析 HTML 文檔的 Python 庫,通過 BeautifulSoup,你只需要用很少的代碼就可以提取出 HTML 中任何感興趣的內(nèi)容,此外,它還有一定的 HTML 容錯能力,對于一個格式不完整的HTML 文檔,它也可以正確處理。
安裝 BeautifulSoup
pip install beautifulsoup4
BeautifulSoup3 被官方放棄維護,你要下載最新的版本 BeautifulSoup4。
HTML 標簽
學習 BeautifulSoup4 前有必要先對 HTML 文檔有一個基本認識,如下代碼,HTML 是一個樹形組織結(jié)構(gòu)。
<html><head><title>hello, world</title></head><body><h1>BeautifulSoup</h1><p>如何使用BeautifulSoup</p><body></html>
它由很多標簽(Tag)組成,比如 html、head、title等等都是標簽
一個標簽對構(gòu)成一個節(jié)點,比如 <html>...</html>是一個根節(jié)點
節(jié)點之間存在某種關(guān)系,比如 h1 和 p 互為鄰居,他們是相鄰的兄弟(sibling)節(jié)點
h1 是 body 的直接子(children)節(jié)點,還是 html 的子孫(descendants)節(jié)點
body 是 p 的父(parent)節(jié)點,html 是 p 的祖輩(parents)節(jié)點
嵌套在標簽之間的字符串是該節(jié)點下的一個特殊子節(jié)點,比如 “hello, world” 也是一個節(jié)點,只不過沒名字。
使用 BeautifulSoup
構(gòu)建一個 BeautifulSoup 對象需要兩個參數(shù),第一個參數(shù)是將要解析的 HTML 文本字符串,第二個參數(shù)告訴 BeautifulSoup 使用哪個解析器來解析 HTML。
解析器負責把 HTML 解析成相關(guān)的對象,而 BeautifulSoup 負責操作數(shù)據(jù)(增刪改查)?!癶tml.parser” 是 Python 內(nèi)置的解析器,“l(fā)xml” 則是一個基于c語言開發(fā)的解析器,它的執(zhí)行速度更快,不過它需要額外安裝
通過 BeautifulSoup 對象可以定位到 HTML 中的任何一個標簽節(jié)點。
from bs4 import BeautifulSouptext="""<html><head><title >hello, world</title></head><body><h1>BeautifulSoup</h1><p class="bold">如何使用BeautifulSoup</p><p class="big" id="key1"> 第二個p標簽</p><a html.parser")# title 標簽>>> soup.title<title>hello, world</title># p 標簽>>> soup.p<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p># p 標簽的內(nèi)容>>> soup.p.stringu'\u5982\u4f55\u4f7f\u7528BeautifulSoup'
BeatifulSoup 將 HTML 抽象成為 4 類主要的數(shù)據(jù)類型,分別是Tag , NavigableString , BeautifulSoup,Comment 。每個標簽節(jié)點就是一個Tag對象,NavigableString 對象一般是包裹在Tag對象中的字符串,BeautifulSoup 對象代表整個 HTML 文檔。例如:
>>> type(soup)<class 'bs4.BeautifulSoup'>>>> type(soup.h1)<class 'bs4.element.Tag'>>>> type(soup.p.string)<class 'bs4.element.NavigableString'>
Tag
每個 Tag 都有一個名字,它對應 HTML 的標簽名稱。
>>> soup.h1.nameu'h1'>>> soup.p.nameu'p'
標簽還可以有屬性,屬性的訪問方式和字典是類似的,它返回一個列表對象
>>> soup.p['class'][u'bold']
NavigableString
獲取標簽中的內(nèi)容,直接使用 .stirng 即可獲取,它是一個 NavigableString 對象,你可以顯式地將它轉(zhuǎn)換為 unicode 字符串。
>>> soup.p.stringu'\u5982\u4f55\u4f7f\u7528BeautifulSoup'>>> type(soup.p.string)<class 'bs4.element.NavigableString'>>>> unicode_str=unicode(soup.p.string)>>> unicode_stru'\u5982\u4f55\u4f7f\u7528BeautifulSoup'
基本概念介紹完,現(xiàn)在可以正式進入主題了,如何從 HTML 中找到我們關(guān)心的數(shù)據(jù)?BeautifulSoup 提供了兩種方式,一種是遍歷,另一種是搜索,通常兩者結(jié)合來完成查找任務(wù)。
遍歷文檔樹
遍歷文檔樹,顧名思義,就是是從根節(jié)點 html 標簽開始遍歷,直到找到目標元素為止,遍歷的一個缺陷是,如果你要找的內(nèi)容在文檔的末尾,那么它要遍歷整個文檔才能找到它,速度上就慢了。因此還需要配合第二種方法。
通過遍歷文檔樹的方式獲取標簽節(jié)點可以直接通過 .標簽名
的方式獲取,例如:
獲取 body 標簽:
>>> soup.body<body>\n<h1>BeautifulSoup</h1>\n<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p>\n</body>
獲取 p 標簽
>>> soup.body.p<p class="bold">\u5982\u4f55\u4f7f\u7528BeautifulSoup</p>
獲取 p 標簽的內(nèi)容
>>> soup.body.p.string\u5982\u4f55\u4f7f\u7528BeautifulSoup
前面說了,內(nèi)容也是一個節(jié)點,這里就可以用 .string的方式得到。
遍歷文檔樹的另一個缺點是只能獲取到與之匹配的第一個子節(jié)點,例如,如果有兩個相鄰的 p 標簽時,第二個標簽就沒法通過 .p的方式獲取,這是需要借用 next_sibling 屬性獲取相鄰的節(jié)點。
此外,還有很多不怎么常用的屬性,比如:.contents 獲取所有子節(jié)點,.parent 獲取父節(jié)點,更多的參考請查看官方文檔。
搜索文檔樹
搜索文檔樹是通過指定標簽名來搜索元素,還可以通過指定標簽的屬性值來精確定位某個節(jié)點元素,最常用的兩個方法就是 find 和 find_all。這兩個方法在 BeatifulSoup 和 Tag 對象上都可以被調(diào)用。
find_all()
find_all( name , attrs , recursive , text , **kwargs )
find_all 的返回值是一個 Tag 組成的列表,方法調(diào)用非常靈活,所有的參數(shù)都是可選的。
第一個參數(shù) name 是標簽節(jié)點的名字。
# 找到所有標簽名為title的節(jié)點>>> soup.find_all("title")
[<title>hello, world</title>]
>>> soup.find_all("p")
[<p class="bold">\xc8\xe7\xba\xce\xca....</p>,
<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p...</p>]
第二個參數(shù)是標簽的class屬性值
# 找到所有class屬性為big的p標簽>>> soup.find_all("p", "big")
[<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]
等效于
>>> soup.find_all("p", class_="big")
[<p class="big"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]
因為 class 是 Python 關(guān)鍵字,所以這里指定為 class_。
kwargs 是標簽的屬性名值對,例如:查找有href屬性值為 “http://foofish.net” 的標簽
>>> soup.find_all()
[<a >python</a>]
當然,它還支持正則表達式
>>> import re>>> soup.find_all(href=re.compile("^http"))
[<a >python</a>]
屬性除了可以是具體的值、正則表達式之外,它還可以是一個布爾值(True/Flase),表示有屬性或者沒有該屬性。
>>> soup.find_all(id="key1")
[<p class="big" id="key1"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]
>>> soup.find_all(id=True)
[<p class="big" id="key1"> \xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9</p>]
遍歷和搜索相結(jié)合查找,先定位到 body 標簽,縮小搜索范圍,再從 body 中找 a 標簽。
>>> body_tag=soup.body>>> body_tag.find_all("a")
[<a >python</a>]
find()
find 方法跟 find_all 類似,唯一不同的地方是,它返回的單個 Tag 對象而非列表,如果沒找到匹配的節(jié)點則返回 None。如果匹配多個 Tag,只返回第0個。
>>> body_tag.find("a")
<a >python</a>
>>> body_tag.find("p")
<p class="bold">\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup</p>
get_text()
獲取標簽里面內(nèi)容,除了可以使用 .string 之外,還可以使用 get_text 方法,不同的地方在于前者返回的一個 NavigableString 對象,后者返回的是 unicode 類型的字符串。
>>> p1=body_tag.find('p').get_text()
實際場景中我們一般使用 get_text 方法獲取標簽中的內(nèi)容。
總結(jié)
BeatifulSoup 是一個用于操作 HTML 文檔的 Python 庫,初始化 BeatifulSoup 時,需要指定 HTML 文檔字符串和具體的解析器。它有3類常用的數(shù)據(jù)類型,分別是 Tag、NavigableString、和 BeautifulSoup。查找 HTML元素有兩種方式,分別是遍歷文檔樹和搜索文檔樹,通??焖佾@取數(shù)據(jù)需要二者結(jié)合。
家好,我是DD,已經(jīng)是封閉在家的第51天了!
最近一直在更新Java新特性(https://www.didispace.com/java-features/)和IDEA Tips(https://www.didispace.com/idea-tips/)兩個原創(chuàng)專欄,其他方向內(nèi)容的動態(tài)關(guān)注少了。昨天天晚上刷推的時候,瞄到了這個神奇的東西,覺得挺cool的,拿出來分享下:
相信你看到圖,不用我說,你也猜到是啥了吧?html里可以跑python代碼了!
看到好多Python公眾號已經(jīng)開始猛吹未來了,但乍看怎么覺得有點像JSP?或者一些模版引擎?是進步還是倒退呢?與其瞎想,不如仔細看看這個東東的能力吧!
根據(jù)官方介紹,這個名為PyScript的框架,其核心目標是為開發(fā)者提供在標準HTML中嵌入Python代碼的能力,使用 Python調(diào)用JavaScript函數(shù)庫,并以此實現(xiàn)利用Python創(chuàng)建Web應用的功能。
看到介紹里提到了調(diào)用JavaScript函數(shù)庫的能力,看來跟JSP或者模版引擎還是有區(qū)別的。
官方給了一個例子,可以幫助我們觀的感受這個開發(fā)框架的能力,不妨跟著DD看看,它能做啥吧!
第一個案例,hello world
代碼很簡單,就下面這幾行。你只需要創(chuàng)建一個html文件,然后復制進去就可以了。
|
保存好之后,在瀏覽器里打開就能看到這樣的頁面了:
回頭再看看這個html里的內(nèi)容,三個核心內(nèi)容:
如果你懶得自己敲代碼的話,本文的兩個案例代碼我打包放在公眾號了,需要的朋友可以關(guān)注公眾號“程序猿DD”,回復:pyscript 獲取。
第二個案例,數(shù)據(jù)定義 + 數(shù)據(jù)展示
先創(chuàng)建一個data.py文件,然后加入前面的代碼。功能很簡單,就是隨機生成(x,y)的坐標
|
再創(chuàng)建一個html文件,加入下面的代碼
|
這里就稍微復雜一些了,除了hello world中的幾個要點外,這里還有這幾個要關(guān)注的地方:
這個頁面的執(zhí)行效果是這樣的:
是不是很神奇呢?整個過程中都沒有大家熟悉的cs、js內(nèi)容,就完成了這樣一個圖的頁面實現(xiàn)。
最后,談?wù)勗谡麄€嘗試過程中,給我的幾個感受:
這個開發(fā)框架目前還只是alpha版本,未來一定還會有更多特性與優(yōu)化出來,總體上我覺得這個框架還是非常cool的,尤其對于剛學會Python,或者只會Python,但又想快速開發(fā)Web應用的小伙伴來說,可能將會是個不錯的選擇,那你覺得這個框架如何?未來會不會火?留言區(qū)聊聊吧!
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。