iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 22
1

昨天發文後想到另一個狀況,是因為系統架構設計的關係,網站上呈現的資料並沒有在第一次發請求時取得,而是在網頁載入後陸續以 AJAX 的方式取得資料顯示在畫面上,或者即時以 JavaScript 計算後顯示。雖然這樣做的目的不一定是為了反爬蟲,但仍然會增加開發爬蟲的困難。今天就來補充說明一下怎麼處理這種狀況吧! 絕對不是想拖稿

用程式操作瀏覽器

如果 JavaScript 都是在瀏覽器載入網頁後才會開始執行,那有沒有辦法在程式中打開瀏覽器,模擬正常使用者的操作之後再把資料抓下來呢?

有三個不錯的方法可以滿足我們的需求,接下來會分別介紹。會以 pythonclock 這個倒數的網站來作為範例。

https://ithelp.ithome.com.tw/upload/images/20191006/20107875x3CRy1UjEv.png

import requests
from bs4 import BeautifulSoup

html_doc = requests.get('https://pythonclock.org/').text
soup = BeautifulSoup(html_doc, 'lxml')

print(soup.find('div', class_='python-27-clock'))

用一般的 requests 方式來抓倒數時間的話,會發現抓到一個空的 div 區塊。

https://ithelp.ithome.com.tw/upload/images/20191006/20107875LROm1rncGo.png

Selenium

Selenium 可以把人操作瀏覽器的過程自動化,透過 WebDriver 的介面來操作不同的瀏覽器,今天以我比較常用的 Chrome 來作範例。

準備環境

  1. 下載 web driver

Chrome 的 web driver 可以到這邊下載,其他瀏覽器可以在官網中找到對應的下載位址。

  1. 安裝 selenium 套件
pipenv install selenium

用程式開啟瀏覽器

from selenium import webdriver
from bs4 import BeautifulSoup

# 指定剛剛下載的 webdriver 路徑
driver = webdriver.Chrome('./chromedriver.exe')
# 用瀏覽器連到 https://pythonclock.org/ 網站
driver.get('https://pythonclock.org/') 

html_doc = driver.text
soup = BeautifulSoup(html_doc, 'lxml')

print(soup.find('div', class_='python-27-clock'))

執行時會發現自動打開 Chrome 瀏覽器並連到指定的網站,此時就可以抓到有內容的區塊了。

https://ithelp.ithome.com.tw/upload/images/20191006/20107875KFcqBLakaj.png

puppeteer

puppeteer 是 Google 開源的 JS 套件,可以用 Headless Chrome 的方式(也就是不會有真的瀏覽器視窗跳出來)來執行 Chrome 瀏覽器。也有大神做了一個 Python 的版本,Pyppeteer,來試試看。

需要搭配 asyncio 使用

  1. 安裝套件
pipenv install pyppeteer
  1. 寫扣
import asyncio
from pyppeteer import launch
from bs4 import BeautifulSoup

async def main():
    # 開啟瀏覽器程序
    browser = await launch()
    # 用瀏覽器連到 https://pythonclock.org/ 網站
    page = await browser.newPage()
    await page.goto('https://pythonclock.org/')    

    html_doc = await page.content()
    soup = BeautifulSoup(html_doc, 'lxml')

    await browser.close()

    print(soup.find('div', class_='python-27-clock'))

asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(main())

(10/6) 今天試的時候一直 timeout...研究一下再更新原因QQ

(10/7) 換了一台電腦就可以了,感覺是 Chromium 在不同環境中執行造成的...

https://ithelp.ithome.com.tw/upload/images/20191007/20107875szeMcr9BGZ.png

requests-html

requests-html 也是一個滿好用的 HTML 剖析套件,同時也支援執行 JavaScript 後的結果。

  1. 安裝套件
pipenv install requests-html
  1. 寫扣
from requests_html import HTMLSession
from bs4 import BeautifulSoup

session = HTMLSession()
r = session.get('https://pythonclock.org/') 

r.html.render()
soup = BeautifulSoup(r.html, 'lxml')

print(soup.find('div', class_='python-27-clock'))

(10/6) 跟 puppeteer 一樣,今天 Chromium 好像怪怪的...

(10/7) requests-html 底層也是呼叫 pyppeteer,所以會有一樣的問題,今天換了一台也可以了

https://ithelp.ithome.com.tw/upload/images/20191007/20107875v5JMlg1Fc8.png


今天介紹了三種用程式模擬瀏覽器操作的方式,因為我主要是使用 headless chrome,所以現在都是用 pyppeteer 比較多,大家可以三種都試試看喔~


上一篇
【Day 20】反反爬蟲
下一篇
【Day 22】Scrapy 簡介
系列文
爬蟲在手、資料我有 - 30 天 Scrapy 爬蟲實戰33

尚未有邦友留言

立即登入留言