Requests-HTML 模組

Requests-HTML 模組

前言

Requests-HTML 模組 是原 Requests 開發者另一個巨大貢獻,他包含所有 Request 模組功能,更重要的是新增加了數據清洗與爬取使用 ajax 動態數據加載網頁的功能,它的觀念是 ajax 動態網頁數據會被加載到 Chromium 瀏覽器網頁,然後爬蟲程式自行在 Chromium 瀏覽器爬取,更多相關資訊可以參考。

大綱

安裝與導入

安裝方式如下

pip install requests-html

請留意程式導入此模組方法如下

import requests_html

可以使用模組屬性 DEFAULT_URL 了解是否安裝此模組成功 

使用者請求 Session

Requests 的 Session 模式可以讓請求對話持續保持,只要使用者與伺服器雙方沒有關閉此連線,就持續存在。Requests-HTML 的請求是承襲 Requests,不過 Requests-HTML 的請求只能使用 Session方式。

使用 Requests 模組時,常用的 get()、post() 方法,也可以應用在 Requests-HTML 模組,同時在 Requests 模組內,使用 get() 、post() 的參數,也可以使用在 Requests-HTML 模組的 get()、post()。所以先前章節介紹的 headers、proxies、cookies...等等的參數,也可以運用在此 get()、post()。此外,偽裝瀏覽器的表頭 headers,如果沒有設定,Requests-HTML 模組會使用預設的表頭 headers。在安裝此模組時,可以看到下列路徑 ~\Python39\Lib\site-packages 的 requests_html.py 檔案。

開啟上述檔案可以看到下列預設的表頭 headers 預設內容:

DEFAULT_ENCODING = 'utf-8'
DEFAULT_URL = 'https://example.org/'
DEFAULT_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'

認識回傳資料型態與幾個重要屬性

Requests-HTML 模組的 get()post() 方法所回傳的節點是類別 class 資料型態此資料型態有 HTML 屬性可以回傳所連結網頁的網址 。

範例 pythonRequestsHtml-01.py:  列出回傳物件屬性的應用,與網頁網址和內容 。

# pythonRequestsHtml-01.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'http://127.0.0.1:5500/htmlExampleBS4-02.html'
r = session.get(url)                # get()
print(type(r))
print(type(r.html))
print(r.html)
print(type(r.html.text))
print('-'*70)
print(r.html.text)

執行結果

<class 'requests_html.HTMLResponse'>
<class 'requests_html.HTML'>
<HTML url='http://127.0.0.1:5500/htmlExampleBS4-02.html'>
<class 'str'>
----------------------------------------------------------------------
htmlExampleBS4-02.html
header { background-color: rgb(218, 180, 231); min-height: 100px; } main { background-color: rgb(239, 238, 238); min-height: 300px; } footer { min-height: 80px; }
這是表頭區塊
這是主要內容區
人物介紹-1
人物介紹-2
人物介紹-3
這是表尾

從上述可以看到 Requests-HTML 模組中回傳物件是類別 class,然後 r.html 是網頁網址,他的資料型態也是類別。其實如果讀者仔細看上述 r.html.text 可以列出字串形式的網頁內容,同時可以看到原先網頁的 HTML 標籤元素沒有了,所以我們也可以說數據中含有 HTML 元素的部分被清洗了。

上述範例的 r.html 物件有屬性 links 儲存網頁裡所有相對位置 URL 網址,absolute_link 儲存所有絕對地址的 URL 網址,下列我們用 Python 官方網站作解說。

範例 pythonRequestsHtml-02.py:  分別列出 https://www.python.org/ 屬性是 links 和 absolute_links 的超連結的數量,同時列出前5個超連結。

# pythonRequestsHtml-02.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'https://python.org/'
r = session.get(url)                # get()
url_links = r.html.links
count = 0
print('相對位址超連結數量 : ', len(url_links))
for link in url_links:
    count += 1
    print(link)
    if count >= 5:
        break
print('-'*70)
url_a_links = r.html.absolute_links
count = 0
print('絕對位址超連結數量 : ', len(url_a_links))
for link in url_a_links:
    count += 1
    print(link)
    if count >= 5:
        break

執行結果

相對位址超連結數量 :  126
http://www.pylonsproject.org/
http://wiki.python.org/moin/TkInter
http://docs.python.org/3/tutorial/introduction.html#using-python-as-a-calculator
//docs.python.org/3/tutorial/controlflow.html
https://blog.python.org
----------------------------------------------------------------------
絕對位址超連結數量 :  126
http://www.pylonsproject.org/
http://wiki.python.org/moin/TkInter
http://docs.python.org/3/tutorial/introduction.html#using-python-as-a-calculator
https://blog.python.org
https://www.python.org/success-stories/category/engineering/

數據清洗與爬取

前面我們可以取得網頁內容,這裡我們將更精準的爬取我們想要的網頁細節內容,可以使用下列幾個方法 

使用 find() 方法

這方法的語法如下

find(selector, containing, clean, first, _encoding)

  • selector : 使用 CSS 定位網頁元素。
  • containing : 使用特定字串尋找網頁節點。
  • clean : 是否清除發現的 <script> 和 <style>。
  • first : 是否找第一個元素,預設是 False,相當於找全部元素。
  • _encoding : 設定編碼格式,預設是無。

接下來我們要使用此文觀念爬取有關下拉式功能表的 "about" 元素,如下列所示  :

如果使用 Chrome 瀏覽器解析上述網頁,可以得到下拉式選單的 HTML 元素,如下列所示  :

範例 pythonRequestsHtml-03.py:  爬取上述表單選項。

# pythonRequestsHtml-03.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'https://python.org/'
r = session.get(url)                # get()
about = r.html.find('#about', first=True)
print(about.text)

執行結果

About
Applications
Quotes
Getting Started
Help
Python Brochure

範例 pythonRequestsHtml-04.py:  列出系列搜尋about的屬性。

# pythonRequestsHtml-04.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'https://python.org/'
r = session.get(url)                # get()
about = r.html.find('#about', first=True)
print('印出 about.attrs屬性 :', about.attrs)
print('-'*70)
print('印出 about.html屬性 :', about.html)
print('-'*70)
print('印出 about.absolute_links屬性 :',about.attrs)
print('-'*70)
print("印出 about.find('a') :",about.find('a'))

執行結果

印出 about.attrs屬性 : {'id': 'about', 'class': ('tier-1', 'element-1'), 'aria-haspopup': 'true'}
----------------------------------------------------------------------
印出 about.html屬性 : <li id="about" class="tier-1 element-1" aria-haspopup="true">
<a href="/about/" title="" class="">About</a>
<ul class="subnav menu" role="menu" aria-hidden="true">
<li class="tier-2 element-1" role="treeitem"><a href="/about/apps/" title="">Applications</a></li>
<li class="tier-2 element-2" role="treeitem"><a href="/about/quotes/" title="">Quotes</a></li>
<li class="tier-2 element-3" role="treeitem"><a href="/about/gettingstarted/" title="">Getting Started</a></li>
<li class="tier-2 element-4" role="treeitem"><a href="/about/help/" title="">Help</a></li>
<li class="tier-2 element-5" role="treeitem"><a href="http://brochure.getpython.info/" title="">Python Brochure</a></li>
</ul>
</li>
----------------------------------------------------------------------
印出 about.absolute_links屬性 : {'id': 'about', 'class': ('tier-1', 'element-1'), 'aria-haspopup': 'true'}
----------------------------------------------------------------------
印出 about.find('a') : [<Element 'a' href='/about/' title='' class=()>, <Element 'a' href='/about/apps/' title=''>, <Element 'a' href='/about/quotes/' title=''>, <Element 'a' href='/about/gettingstarted/' title=''>, <Element 'a' href='/about/help/' title=''>, <Element 'a' href='http://brochure.getpython.info/' title=''>]

find() 方法可以有參數 containing=’xx’,設定含某字串,用法可以參考下列範例 : 

範例 pythonRequestsHtml-05.py:  設定搜尋含字串 ”kenneth” 的<a> 元素  。

# pythonRequestsHtml-05.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'http://python-requests.org/'
r = session.get(url)                # get()
a_element = r.html.find('a', containing='kenneth')
if a_element:
    for a in a_element:
        print(a)

執行結果

<Element 'a' href='https://kenreitz.org/projects'>
<Element 'a' class=('reference', 'internal') href='dev/contributing/#kenneth-reitz-s-code-style'>

使用 xpath() 方法

此方法的語法如下

xpath(selector, clean, first, _encoding)

  • selector : 使用 xpath 定位網頁元素。
  • clean : 是否清除發現的 <script> 和 <style>。
  • first : 是否找第一個元素,預設是 False,相當於找全部元素。
  • _encoding : 設定編碼格式,預設是無。

範例 pythonRequestsHtml-06.py:  xpath() 方法的應用 。

# pythonRequestsHtml-06.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'https://python.org/'
r = session.get(url)                # get()
a_element = r.html.xpath('//a')
if a_element:
    for a in a_element:
        print(a)
        print('-'*70)

執行結果

<Element 'a' href='#content' title='Skip to content'>
----------------------------------------------------------------------
<Element 'a' id='close-python-network' class=('jump-link',) href='#python-network' aria-hidden='true'>
.......以下省略.....

搜尋 search()

這功能可以搜尋 HTML 文件本文,可以參考下列實例。

範例 pythonRequestsHtml-07.py:  search() 搜尋本文的應用。

# pythonRequestsHtml-07.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'https://python.org/'
r = session.get(url)                # get()
txt = r.html.search('Python is a {} language')[0] 
print(txt)

執行結果

programming

搜尋豆瓣電影網站

請進入 豆瓣電影網站,影片會自行輪播目前播放的影片,請進入 Chrome 開發模式,可以看到下列訊息 :

從上述可以看到第一部影片的名稱可以用 li.title 表示,評分可以用 li.rating 表示,有了上述數據我們就可以爬取第一部影片的名稱與評分。

範例 pythonRequestsHtml-08.py:  列出豆瓣電影網站第一部影片和評分。

# pythonRequestsHtml-08.py
from requests_html import HTMLSession

session = HTMLSession()
url = 'https://movie.douban.com/'
r = session.get(url)

print('影片名稱 : ', r.html.find('li.title', first=True).text)
print('影片評分 : ', r.html.find('li.rating', first=True).text)

執行結果

影片名稱 :  沙丘
影片評分 :  7.9

Chrome 開發模式可以看到所有影片是在 <li class="ui-slide-item s"......>,所以如果我們想要爬取全部影片與評分數據,也可以由上方區塊著手。

範例 pythonRequestsHtml-09.py:  使用不同方式列出上方區塊的電影名稱和評分。

# pythonRequestsHtml-09.py
from requests_html import HTMLSession

session = HTMLSession()
url = 'https://movie.douban.com/'
r = session.get(url)

movies = r.html.find('li.ui-slide-item')
print('影片數量 : ', len(movies))
print('數據型態 : ', type(movies[0]))
print(movies[0])
print('-'*70)
print(movies[0].attrs['data-title'])
print(movies[0].attrs['data-rate'])

執行結果

影片數量 :  112
數據型態 :  <class 'requests_html.Element'>
<Element 'li' class=('ui-slide-item', 's') data-dstat-areaid='70_1' data-dstat-mode='click,expose' data-dstat-watch='.ui-slide-content' data-dstat-viewport='.screening-bd' data-title='沙丘 Dune' data-release='2021' data-rate='7.9' data-star='40' data-trailer='https://movie.douban.com/subject/3001114/trailer' data-ticket='https://movie.douban.com/ticket/redirect/?movie_id=3001114' data-duration='156分钟' data-region='美国' data-director='丹尼斯·维伦纽瓦' data-actors='蒂莫西·柴勒梅德 / 丽贝卡·弗格森 / 奥斯卡·伊萨克' data-intro='' data-enough='true' data-rater='10815'>
----------------------------------------------------------------------
沙丘 Dune
7.9

範例 pythonRequestsHtml-10.py:  列出前5部影片和評分 。

# pythonRequestsHtml-10.py
from requests_html import HTMLSession

session = HTMLSession()
url = 'https://movie.douban.com/'
r = session.get(url)

movies = r.html.find('li.ui-slide-item')
count = 0
for m in movies:
    count += 1
    print('影片編號 : ', count)
    print('影片名稱 : ', m.attrs['data-title'])
    print('影片評分 : ', m.attrs['data-rate'])
    print('-'*70)
    if count == 5:
        break

執行結果

影片編號 :  1
影片名稱 :  沙丘 Dune
影片評分 :  7.9
----------------------------------------------------------------------
影片編號 :  2
影片名稱 :  兰心大剧院
影片評分 :  7.4
----------------------------------------------------------------------
影片編號 :  3
影片名稱 :  图兰朵:魔咒缘起
影片評分 :  3.6
----------------------------------------------------------------------
影片編號 :  4
影片名稱 :  长津湖
影片評分 :  7.4
----------------------------------------------------------------------
影片編號 :  5
影片名稱 :  我和我的父辈
影片評分 :  6.9
----------------------------------------------------------------------

Ajax 動態數據加載

在使用 Requests-HTML 執行網站頁面請求,伺服器回應的內容與 Chrome 開發工具的內容是一致的,如果網頁是使用 ajax 動態加載,也就是由 JavaScript 處理,則需要 Requests-HTML 模組 ajax 動態加載請求,才可以獲得加載數據。

模擬執行 ajax 動態加載需要借助 Google 的 Chromium 瀏覽器,同時搭配 render() 方法,在第一次執行 render() 時,Chromium 瀏覽器會被自動下載到你的工作平台目錄.....,不過下載速度超級慢。

在執行 render() 時,被請求網站使用 ajax 動態加載的數據會被下載到 Chromium 瀏覽器,爬蟲程式可以由此 Chromium 瀏覽器讀取所有的網路數據。

Chromium 瀏覽器是 Google 為了 Chrome 瀏覽器展開的計劃,所有新功能皆是在 Chromium 瀏覽器上測試,認證成功後再移植到 Chrome瀏覽器。

範例 pythonRequestsHtml-11.py:  下列 Requests-HTML 官網,是使用 Requests-HTML 模組的 render() 執行下載 ajax 動態數據的實例。

# pythonRequestsHtml-11.py
from requests_html import HTMLSession

session = HTMLSession()             # 定義Session
url = 'http://python-requests.org/'
r = session.get(url)                # get()
r.html.render()
txt =  r.html.search('Python 2 will retire in only {months} months!')['months']
print(txt)


參考資料

特色、摘要,Feature、Summary:

關鍵字、標籤,Keyword、Tag:

  • Web-Crawler,Data-Mining,Data-Science,Python,

留言

這個網誌中的熱門文章

Ubuntu 常用指令、分類與簡介

iptables的觀念與使用

網路設定必要參數IP、netmask(遮罩)、Gateway(閘道)、DNS

了解、分析登錄檔 - log

Python 與SQLite 資料庫

Blogger文章排版範本

Pandas 模組

如何撰寫Shell Script

查詢指令或設定 -Linux 線上手冊 - man

下載網頁使用 requests 模組