Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
X0
HTTP(HyperText Transfer Protocol)超文本傳輸協(xié)議,是web服務(wù)器到web瀏覽器之間傳輸?shù)耐ㄐ乓?guī)則。
0x01
HTTP協(xié)議目前最新版本是1.1,HTTP是一種無(wú)狀態(tài)的協(xié)議,只能由客戶端發(fā)起,服務(wù)器端不能主動(dòng)向客戶端發(fā)送數(shù)據(jù)。
應(yīng)答模型:
Request請(qǐng)求
客戶端=============》服務(wù)端
《============
Response響應(yīng)
0x02 HTTP請(qǐng)求
包括三個(gè)部分:1、請(qǐng)求行; 2、請(qǐng)求頭; 3、請(qǐng)求正文。
實(shí)例:
GET /notification/notification_count/ HTTP/1.1 請(qǐng)求行
Host: mp.xxxxxx.com 請(qǐng)求頭
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0 (User-Agent代表瀏覽器標(biāo)識(shí)。)
Accept: application/json, text/javascript, */*; q=0.01 正文
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://mp.toutiao.com/profile_v2/publish
X-Requested-With: XMLHttpRequest
圖例brupsuite:
使用python socket測(cè)試http響應(yīng)的效果:
import socket
t_host="www.toutiao.com"
t_port=80
client=socket.socket()
client.connect((t_host,t_port))
client.send("GET / HTTP/1.1\r\nHost:toutiao.com\r\n\r\n")
response=client.recv(4096)
print response
HTTP/1.1 502 Bad Gateway //響應(yīng)行 HTTP的版, 狀態(tài)碼 502,消息是Bad Gateway
Server: Tengine //響應(yīng)頭 由服務(wù)器向客戶端發(fā)送
Content-Length: 0
Connection: keep-alive
Via: cache5.cn218[0,502-257,M], cache4.cn218[14,1,502001]
X-Swift-Error: dns domain not exist
Timing-Allow-Origin: *
EagleId: 790e0d0415057759521686693e
........由于response獲取的字節(jié)有限下面是響應(yīng)正文,是服務(wù)器向客戶端發(fā)送的HTML數(shù)據(jù)。
EOF:下一遍我將講述HTTP的請(qǐng)求方法,請(qǐng)期待。
碼如下:
import requests from bs4 import BeautifulSoup import pandas as pd #下面是請(qǐng)求數(shù)據(jù) url="https://www.163.com/" #設(shè)置請(qǐng)求網(wǎng)址為搜索網(wǎng)址 response=requests.get(url) #對(duì)163網(wǎng)站就行g(shù)et請(qǐng)求并將請(qǐng)求結(jié)果賦值給response response.encoding="GBK" #設(shè)置編碼為GBK格式的 html=response.text #獲取網(wǎng)頁(yè)的html源代碼并賦值給html #下面是解析數(shù)據(jù) soup=BeautifulSoup(html) content=soup.findAll('div') #查找所有的div標(biāo)簽內(nèi)容并賦值給content print(content) #打印content
代碼運(yùn)行結(jié)果如下圖所示:
多朋友都聽(tīng)說(shuō)過(guò)Python的大名,而Python也擁有眾多的爬蟲(chóng)框架,其中最簡(jiǎn)單的莫過(guò)于requests-html了。它和著名的網(wǎng)絡(luò)請(qǐng)求庫(kù)requests是同一個(gè)作者,著重于XML數(shù)據(jù)提取,可以說(shuō)是最簡(jiǎn)單的爬蟲(chóng)框架了。
安裝這個(gè)類庫(kù)非常簡(jiǎn)單,直接通過(guò)pip就可以安裝了。
pip install requests-html
requests-html用起來(lái)也十分簡(jiǎn)單,下面是一個(gè)簡(jiǎn)單例子。照例說(shuō)明一下,第一段引入了HTMLSession用于創(chuàng)建連接,獲取網(wǎng)頁(yè)數(shù)據(jù)。第二段創(chuàng)建連接,獲取了我的簡(jiǎn)書(shū)用戶頁(yè)面。第三段用xpath語(yǔ)法獲取了網(wǎng)頁(yè)上的用戶名,最后打印出來(lái)。
from requests_html import HTMLSession
session=HTMLSession()
response=session.get(
'https://www.jianshu.com/u/7753478e1554')
username=response.html.xpath(
'//a[@class="name"]/text()', first=True)
print(username)
看起來(lái)是不是很簡(jiǎn)單?沒(méi)錯(cuò),確實(shí)很簡(jiǎn)單,接下來(lái)還有一些更加有趣的功能。
編寫爬蟲(chóng)之前還要做一件事情,就是分析網(wǎng)頁(yè)的結(jié)構(gòu)。這個(gè)工作其實(shí)也很簡(jiǎn)單,打開(kāi)你要訪問(wèn)的網(wǎng)頁(yè),按F12打開(kāi)開(kāi)發(fā)人員工具,可以看到最左邊有這么一個(gè)按鈕。點(diǎn)擊這個(gè)按鈕,然后點(diǎn)擊網(wǎng)頁(yè)上你想要查看的網(wǎng)頁(yè)元素,然后你就可以發(fā)現(xiàn)這個(gè)元素對(duì)應(yīng)的相關(guān)源代碼已經(jīng)為你定位完畢了。
定位按鈕
通過(guò)這個(gè)功能,我們就可以輕松的分析網(wǎng)頁(yè),然后通過(guò)它的結(jié)構(gòu)來(lái)編寫爬蟲(chóng)了。
上面的response.html即是網(wǎng)頁(yè)的根節(jié)點(diǎn)HTML節(jié)點(diǎn),在節(jié)點(diǎn)對(duì)象上可以調(diào)用一些方法來(lái)檢索數(shù)據(jù)。最常用的方法是find方法,它通過(guò)CSS選擇器來(lái)定位數(shù)據(jù)。對(duì)于上面的例子,可以用find方法改寫第三段。
因?yàn)樗胁檎曳椒ǚ祷氐慕Y(jié)果都是列表,所以如果你確定只需要查找一個(gè),就將first參數(shù)設(shè)為真來(lái)只返回第一個(gè)結(jié)果。find方法返回的仍然是一個(gè)節(jié)點(diǎn),如果只需要節(jié)點(diǎn)的內(nèi)容,調(diào)用其text屬性即可。
用戶名對(duì)應(yīng)的HTML結(jié)構(gòu)如圖所示。
代碼如下。
username = response.html.find('a.name', first=True).text
除了find方法之外,還可以使用xpath方法用xpath語(yǔ)法來(lái)查找節(jié)點(diǎn),正如第一個(gè)例子那樣。我個(gè)人比較喜歡xpath語(yǔ)法,CSS選擇器雖然更加流行一些,但是寫出來(lái)的效果有點(diǎn)怪,不如xpath工整。
同樣是這個(gè)頁(yè)面,看看如何獲取我的簡(jiǎn)書(shū)的個(gè)人簡(jiǎn)介。網(wǎng)頁(yè)代碼如圖所示。
代碼如下。
description=response.html.xpath(
'//div[@class="description"]/div[@class="js-intro"]/text()', first=True)
CSS選擇器和XPATH語(yǔ)法都不是本篇的主要內(nèi)容,如果你這方面不太熟悉,最好去看一下相關(guān)的教程。當(dāng)然如果大家有什么疑問(wèn)的話,也可以提出來(lái)。假如大家想看的話,我也可以專門寫一篇文章介紹一下這些語(yǔ)法知識(shí)。
有些網(wǎng)頁(yè)利用了前后端分離技術(shù)開(kāi)發(fā)的,需要瀏覽器渲染才能完整顯示。如果用爬蟲(chóng)去看的話,只能顯示一部分內(nèi)容。這時(shí)候就需要瀏覽器渲染頁(yè)面,才能獲取完整的頁(yè)面。用requests-html的話,這個(gè)過(guò)程非常簡(jiǎn)單。
首先先來(lái)看看一個(gè)需要渲染網(wǎng)頁(yè)的例子。下面的代碼訪問(wèn)了我的簡(jiǎn)書(shū)用戶頁(yè)面,然后嘗試獲取我的所有文章。但是如果你運(yùn)行這個(gè)例子的話,就會(huì)發(fā)現(xiàn)只能獲取前幾項(xiàng)。因?yàn)楹?jiǎn)書(shū)的頁(yè)面正是一個(gè)典型的需要瀏覽器渲染的頁(yè)面,爬蟲(chóng)獲取到的網(wǎng)頁(yè)是不完整的。
from requests_html import HTMLSession
session=HTMLSession()
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.119 Safari/537.36'
}
url='https://www.jianshu.com/u/7753478e1554'
r=session.get(url, headers=headers)
for a in r.html.xpath('//ul[@class="note-list"]/li/div[@class="content"]/a[@class="title"]'):
title=a.text
link=f'https://www.jianshu.com{a.attrs["href"]}'
print(f'《{title}》,{link}')
那么如何渲染網(wǎng)頁(yè)來(lái)獲取完整的結(jié)果呢?其實(shí)非常簡(jiǎn)單,在查詢HTML節(jié)點(diǎn)之前,調(diào)用render函數(shù)即可。
render函數(shù)來(lái)使用瀏覽器渲染
原理也非常簡(jiǎn)單,第一次調(diào)用render的時(shí)候,requests-html會(huì)在本地下載一個(gè)chromium瀏覽器,用它來(lái)渲染網(wǎng)頁(yè)。如此一來(lái),我們就可以獲取到渲染之后的頁(yè)面了。
但是對(duì)于簡(jiǎn)書(shū)這個(gè)例子來(lái)說(shuō)還是有些問(wèn)題,因?yàn)槿绻阍跒g覽器里打開(kāi)這個(gè)網(wǎng)頁(yè)的話,會(huì)發(fā)現(xiàn)一些文章在瀏覽器下滑頁(yè)面的時(shí)候才開(kāi)始渲染。不過(guò)聰慧的作者早就考慮到這種情況了,render函數(shù)支持下滑的參數(shù),設(shè)定之后,就會(huì)模擬瀏覽器下滑操作,從而解決了這個(gè)問(wèn)題。
r.html.render(scrolldown=50, sleep=0.2)
不論上面的r.html還是find/xpath函數(shù)返回的結(jié)果,它們都是節(jié)點(diǎn)對(duì)象。除了上面介紹的幾個(gè)提取數(shù)據(jù)的方法以外,節(jié)點(diǎn)對(duì)象還有以下一些屬性,在我們提取數(shù)據(jù)的時(shí)候也有很大作用。
相較于專業(yè)的爬蟲(chóng)框架scrapy,或者僅用于解析XML的解析庫(kù)BeautifulSoup。requests-html可以是說(shuō)恰到好處,它沒(méi)有前者那么難學(xué),也不像后者還需要搭配HTTP請(qǐng)求庫(kù)才能使用。如果你手頭需要臨時(shí)抓取幾個(gè)網(wǎng)頁(yè),那么requests-html就是你最好的選擇。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。