1. 程式人生 > 程式設計 >python爬蟲 requests-html的使用

python爬蟲 requests-html的使用

一 介紹

  Python上有一個非常著名的HTTP庫——requests,相信大家都聽說過,用過的人都說非常爽!現在requests庫的作者又釋出了一個新庫,叫做requests-html,看名字也能猜出來,這是一個解析HTML的庫,具備requests的功能以外,還新增了一些更加強大的功能,用起來比requests更爽!接下來我們來介紹一下它吧。

# 官網解釋
'''
This library intends to make parsing HTML (e.g. scraping the web) as simple and intuitive as possible.
If you're interested in financially supporting Kenneth Reitz open source,consider visiting this link. Your support helps tremendously with sustainability of motivation,as Open Source is no longer part of my day job.
When using this library you automatically get:

Full JavaScript support!
CSS Selectors (a.k.a jQuery-style,thanks to PyQuery).
XPath Selectors,for the faint at heart.
Mocked user-agent (like a real web browser).
Automatic following of redirects.
Connection–pooling and cookie persistence.
The Requests experience you know and love,with magical parsing abilities.
Async Support
'''

官網告訴我們,它比原來的requests模組更加強大,並且為我們提供了一些新的功能!

  • 支援JavaScript
  • 支援CSS選擇器(又名jQuery風格,感謝PyQuery)
  • 支援Xpath選擇器
  • 可自定義模擬User-Agent(模擬得更像真正的web瀏覽器)
  • 自動追蹤重定向
  • 連線池與cookie持久化
  • 支援非同步請求

二 安裝

  安裝requests-html非常簡單,一行命令即可做到。需要注意一點就是,requests-html只支援Python 3.6或以上的版本,所以使用老版本的Python的同學需要更新一下Python版本了。

# pip3 install requests-html

三 如何使用requests-html?

  在我們學爬蟲程式的時候用得最多的請求庫就是requests與urllib,但問題是這些包只給我們提供瞭如何去目標站點發送請求,然後獲取響應資料,接著再利用bs4或xpath解析庫才能提取我們需要的資料。

以往爬蟲的請求與解析

import requests
from bs4 import BeautifulSoup
url = 'http://www.zuihaodaxue.cn/'
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/74.0.3729.157 Safari/537.36'
}
response = requests.get(url,headers=HEADERS)
response.encoding = 'gbk'
# print(response.status_code)
 print(response.text)

soup = BeautifulSoup(response.text,'lxml')
# 獲取最新的五則新聞
post_rankings = soup.find_all(name='article',attrs={"class": "post_ranking"})
# 迴圈列印新聞簡介內容
for post_ranking in post_rankings:
new = post_ranking.find(name='div',attrs={"class": 'post_summary'})
print(new.text)

  而在requests-html裡面只需要一步就可以完成而且可以直接進行js渲染!requests的作者Kenneth Reitz 開發的requests-html 爬蟲包 是基於現有的框架 PyQuery、Requests、lxml、beautifulsoup4等庫進行了二次封裝,作者將Requests的簡單,便捷,強大又做了一次升級。

  requests-html和其他解析HTML庫最大的不同點在於HTML解析庫一般都是專用的,所以我們需要用另一個HTTP庫先把網頁下載下來,然後傳給那些HTML解析庫。而requests-html自帶了這個功能,所以在爬取網頁等方面非常方便。  

1、基本使用

from requests_html import HTMLSession
# 獲取請求物件
session = HTMLSession()
# 往新浪新聞主頁傳送get請求
sina = session.get('https://news.sina.com.cn/')
# print(sina.status_code)
sina.encoding = 'utf-8'
# 獲取響應文字資訊,與requests無區別
 print(sina.text)

2、獲取連結(links與abolute_links)

links返回的結果

python爬蟲 requests-html的使用

absolute_links返回的結果

python爬蟲 requests-html的使用

from requests_html import HTMLSession
# 獲取請求物件
session = HTMLSession()
# 往京東主頁傳送get請求
jd = session.get('https://jd.com/')
# 得到京東主頁所有的連結,返回的是一個set集合
print(jd.html.links)
print('*' * 1000)
# 若獲取的連結中有相對路徑,我們還可以通過absolute_links獲取所有絕對連結
print(jd.html.absolute_links)

3、CSS選擇器與XPATH

  request-html支援CSS選擇器和XPATH兩種語法來選取HTML元素。首先先來看看CSS選擇器語法,它需要使用HTML的find函式來查詢元素。

'''
  CSS選擇器 and XPATH
   1.通過css選擇器選取一個Element物件
   2.獲取一個Element物件內的文字內容
   3.獲取一個Element物件的所有attributes
    4.渲染出一個Element物件的HTML內容
   5.獲取Element物件內的特定子Element物件,返回列表
   6.在獲取的頁面中通過search查詢文字
    7.支援XPath
    8.獲取到只包含某些文字的Element物件
'''
from requests_html import HTMLSession
session = HTMLSession()
url = "https://www.qiushibaike.com/text/"
# 獲取響應資料物件
obj = session.get(url)
# 1.通過css選擇器選取一個Element物件
 獲取id為content-left的div標籤,並且返回一個物件
content = obj.html.find('div#content-left',first=True)
# 2.獲取一個Element物件內的文字內容
 獲取content內所有文字
print(content.text)
# 3.獲取一個Element物件的所有attributes
 獲取content內所有屬性
print(content.attrs)
# 4.渲染出一個Element物件的完整的HTML內容
html = content.html
print(html)
# 5.獲取Element物件內的指定的所有子Element物件,返回列表
a_s = content.find('a')
print(a_s)
print(len(a_s)) # 79
# 迴圈所有的a標籤
for a in a_s:
# 獲取a標籤內所有屬性的href屬性 並拼接
href = a.attrs['href']
if href.startswith('/'):
url = 'https://www.qiushibaike.com' + href
print(url)
# 6.在獲取的頁面中通過search查詢文字
 {}大括號相當於正則的從頭到後開始匹配,獲取當中想要獲取的資料
text = obj.html.search('把{}夾')[0] # 獲取從 "把" 到 "夾" 字的所有內容
text = obj.html.search('把糗事{}夾')[0] # 獲取從把子到夾字的所有內容
print(text)
print('*' * 1000)
# 7.支援XPath
a_s = obj.html.xpath('//a') # 獲取html內所有的a標籤
for a in a_s:
href = a.attrs['href']
#若是//開頭的url都扔掉
if href.startswith('continue#若是/開頭的都是相對路徑)
 elif href.startswith('/')
 print('https://www.qiushibaike.com'+href)

# 8.獲取到只包含某些文字的Element物件(containing)
 獲取所有文字內容為幽默笑話大全_爆笑笑話_笑破你的肚子的搞笑段子 - 糗事百科 title標籤
 注意: 文字內有空格也必須把空格帶上
title = obj.html.find('title',containing='幽默笑話大全_爆笑笑話_笑破你的肚子的搞笑段子 - 糗事百科')
print(title)

四支援JavaScript

  支援JavaScript是我覺得作者更新後最為牛逼的一個地方,但是需要在第一次執行render的時候下載chromeium,然後通過它來執行js程式碼。

1、render的使用

from requests_html import HTMLSession
session = HTMLSession()
url = 'http://www.win4000.com/'
obj = session.get(url)
obj.encoding = 'utf-8'
obj.html.render()

  注意:第一次執行render()方法時,它會將Chromium下載到您的主目錄中(例如~/.pyppeteer/)。這種情況只發生一次。

2、 下載Chromeium問題

  因為是從國外的站點下載幾分鐘才3%,實在是太慢了。所以我們需要通過國內的映象去下載!需要做以下幾步:

手動下載Chrome

先去國內源下載自己需要的版本,地址:https://npm.taobao.org/mirrors/chromium-browser-snapshots/

python爬蟲 requests-html的使用

修改chromeium_downloader.py檔案

下載後之後解壓後,進入python安裝目錄下的\Lib\site-packages\pyppeteer目錄,並開啟chromium_downloader.py檔案。

# 找到自己的作業系統相應的配置位置
'''
chromiumExecutable = {
'linux': DOWNLOADS_FOLDER / REVISION / 'chrome-linux' / 'chrome','mac': (DOWNLOADS_FOLDER / REVISION / 'chrome-mac' / 'Chromium.app' /
'Contents' / 'MacOS' / 'Chromium'),'win32': DOWNLOADS_FOLDER / REVISION / 'chrome-win32' / 'chrome.exe','win64': DOWNLOADS_FOLDER / REVISION / 'chrome-win32' / 'chrome.exe',}
'''
from pyppeteer import __chromium_revision__,__pyppeteer_home__
DOWNLOADS_FOLDER = Path(pyppeteer_home) / 'local-chromium'
REVISION = os.environ.get('PYPPETEER_CHROMIUM_REVISION',chromium_revision)
# 列印這兩個變數可以知道執行的驅動具體位置
print(DOWNLOADS_FOLDER)
print(REVISION)
'''
由上面可以知道:chromium路徑是:C:\Users\Ray\AppData\Local\pyppeteer\pyppeteer\local-chromium\575458\chrome-win32\chrome.exe
所以自己建資料夾,然後一直到chrome-win32資料夾,把上面下載的chromium檔案,拷貝到此目錄下
'''

五 自定義User-Agent

  有些網站會使用User-Agent來識別客戶端型別,有時候需要偽造UA來實現某些操作。如果檢視文件的話會發現HTMLSession上的很多請求方法都有一個額外的引數**kwargs,這個引數用來向底層的請求傳遞額外引數。我們先向網站傳送一個請求,看看返回的網站資訊。

from requests_html import HTMLSession
# pprint可以把資料列印得更整齊
from pprint import pprint
import json
get_url = 'http://httpbin.org/get'
session = HTMLSession()
# 返回的是當前系統的headers資訊
res = session.get(get_url)
pprint(json.loads(res.html.html))
# 可以在傳送請求的時候更換user-agent
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0'
post_url = 'http://httpbin.org/get'
res = session.get(post_url,headers={'user-agent': ua})
pprint(json.loads(res.html.html))# 如果你有需要可以在header中修改其他引數。

六 模擬表單提交(POST)

  HTMLSession封裝了一整套的HTTP方法,包括get、post、delete等,對應HTTP中各個方法。

# 表單登入
r = session.post('http://httpbin.org/post',data={'username': 'tank_jam','password': 'tank9527'})
pprint(json.loads(r.html.html))
''' # 列印結果
{'args': {},'data': '','files': {},'form': {'password': 'tank9527','username': 'tank_jam'},'headers': {'Accept': '*/*','Accept-Encoding': 'gzip,deflate','Content-Length': '35','Content-Type': 'application/x-www-form-urlencoded','Host': 'httpbin.org','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) '
       'AppleWebKit/603.3.8 (KHTML,like Gecko) '
       'Version/10.1.2 Safari/603.3.8'},'json': None,'origin': '112.65.61.109,112.65.61.109','url': 'https://httpbin.org/post'}
'''

七 支援非同步請求

  requests-html內部就封裝好了aynsc非同步請求的功能,可以提高我們的爬蟲效率。

from requests_html import AsyncHTMLSession
from requests_html import HTMLSession
import time
# 使用非同步傳送請求
async_session = AsyncHTMLSession()
async def get_baidu():
url = 'https://www.baidu.com/'
res = await async_session.get(url)
print(res.html.absolute_links)
async def get_sougou():
url = 'https://www.sogou.com/'
res = await async_session.get(url)
print(res.html.links)
start_time = time.time()
async_session.run(get_baidu,get_sougou)
print('耗時:',time.time() - start_time)
# 同步傳送請求
session = HTMLSession()
start_time = time.time()
res = session.get('https://www.baidu.com/')
print(res.html.links)
res = session.get('https://www.sogou.com/')
print(res.html.absolute_links)
print('耗時:',time.time() - start_time)

1. 開始

Python 中可以進行網頁解析的庫有很多,常見的有 BeautifulSoup 和 lxml 等。在網上玩爬蟲的文章通常都是介紹 BeautifulSoup 這個庫,我平常也是常用這個庫,最近用 Xpath 用得比較多,使用 BeautifulSoup 就不大習慣,很久之前就知道 Reitz 大神出了一個叫 Requests-HTML 的庫,一直沒有興趣看,這回可算歹著機會用一下了。

使用 pip install requests-html安裝,上手和 Reitz 的其他庫一樣,輕鬆簡單:

 from requests_html import HTMLSession
 session = HTMLSession()
 ​
 r = session.get('https://www.python.org/jobs/')

這個庫是在 requests 庫上實現的,r 得到的結果是 Response 物件下面的一個子類,多個一個 html 的屬性。所以 requests 庫的響應物件可以進行什麼操作,這個 r 也都可以。如果需要解析網頁,直接獲取響應物件的 html 屬性:

r.html

2. 原理

不得不膜拜 Reitz 大神太會組裝技術了。實際上 HTMLSession 是繼承自 requests.Session 這個核心類,然後將 requests.Session 類裡的 requests 方法改寫,返回自己的一個 HTMLResponse 物件,這個類又是繼承自 requests.Response,只是多加了一個 _from_response 的方法來構造例項:

class HTMLSession(requests.Session):
  # 重寫 request 方法,返回 HTMLResponse 構造
  def request(self,*args,**kwargs) -> HTMLResponse:
   r = super(HTMLSession,self).request(*args,**kwargs)
   return HTMLResponse._from_response(r,self)
 class HTMLResponse(requests.Response):
 # 構造器
  @classmethod
  def _from_response(cls,response,session: Union['HTMLSession','AsyncHTMLSession']):
   html_r = cls(session=session)
   html_r.__dict__.update(response.__dict__)
   return html_r

之後在 HTMLResponse 裡定義屬性方法 html,就可以通過 html 屬性訪問了,實現也就是組裝 PyQuery 來幹。核心的解析類也大多是使用 PyQuery 和 lxml 來做解析,簡化了名稱,挺討巧的。

3. 元素定位

元素定位可以選擇兩種方式:

css 選擇器

  • css選擇器
  • xpath
 # css 獲取有多少個職位
 jobs = r.html.find("h1.call-to-action")
 # xpath 獲取
 jobs = r.html.xpath("//h1[@class='call-to-action']")

方法名非常簡單,符合 Python 優雅的風格,這裡不妨對這兩種方式簡單的說明:

4. CSS 簡單規則

  • 標籤名 h1
  • id 使用 #id 表示
  • class 使用 .class_name 表示
  • 謂語表示:h1[prop=value]

5. Xpath簡單規則

  • 路徑 // 或者 /
  • 標籤名
  • 謂語 [@prop=value]
  • 軸定位 名稱::元素名[謂語]

定位到元素以後勢必要獲取元素裡面的內容和屬性相關資料,獲取文字:

 jobs.text
 jobs.full_text

獲取元素的屬性:

 attrs = jobs.attrs
 value = attrs.get("key")

還可以通過模式來匹配對應的內容:

 ## 找某些內容匹配
 r.html.search("Python {}")
 r.html.search_all()

這個功能看起來比較雞肋,可以深入研究優化一下,說不定能在 github 上混個提交。

6. 人性化操作

除了一些基礎操作,這個庫還提供了一些人性化的操作。比如一鍵獲取網頁的所有超連結,這對於整站爬蟲應該是個福音,URL 管理比較方便:

 r.html.absolute_links
 r.html.links

內容頁面通常都是分頁的,一次抓取不了太多,這個庫可以獲取分頁資訊:

 print(r.html)
 # 比較一下
 for url in r.html:
  print(url)
 ​

結果如下:

# print(r.html)
 <HTML url='https://www.python.org/jobs/'>
 # for
 <HTML url='https://www.python.org/jobs/'>
 <HTML url='https://www.python.org/jobs/?page=2'>
 <HTML url='https://www.python.org/jobs/?page=3'>
 <HTML url='https://www.python.org/jobs/?page=4'>
 <HTML url='https://www.python.org/jobs/?page=5'>

通過迭代器實現了智慧發現分頁,這個迭代器裡面會用一個叫 _next 的方法,貼一段原始碼感受下:

 def get_next():
 candidates = self.find('a',containing=next_symbol)
 ​
 for candidate in candidates:
 if candidate.attrs.get('href'):
 # Support 'next' rel (e.g. reddit).
 if 'next' in candidate.attrs.get('rel',[]):
 return candidate.attrs['href']

通過查詢 a 標籤裡面是否含有指定的文字來判斷是不是有下一頁,通常我們的下一頁都會通過 下一頁 或者 載入更多 來引導,他就是利用這個標誌來進行判斷。預設的以列表形式存在全域性:['next','more','older']。我個人認為這種方式非常不靈活,幾乎沒有擴充套件性。感興趣的可以往 github 上提交程式碼優化。

7. 載入 js

也許是考慮到了現在 js 的一些非同步載入,這個庫支援 js 執行時,官方說明如下:

Reloads the response in Chromium,and replaces HTML contentwith an updated version,with JavaScript executed.

使用非常簡單,直接呼叫以下方法:

r.html.render()

第一次使用的時候會下載 Chromium,不過國內你懂的,自己想辦法去下吧,就不要等它自己下載了。render 函式可以使用 js 指令碼來操作頁面,滾動操作單獨做了引數。這對於上拉載入等新式頁面是非常友好的。

8. 總結

Reitz 大神設計出來的東西還是一如既往的簡單好用,自己不多做,大多用別人的東西組裝,簡化 api。真是夠人性。不過有的地方還是優化空間,希望有興趣和精力的童鞋去 github 上關注一下這個專案。

到此這篇關於python爬蟲 requests-html的使用的文章就介紹到這了,更多相關python requests-html內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!