今天介紹下如何使用pyppeteer
抓取網頁的數據。pyppeteer
是web應用自動化測試的具,可以直接運行在瀏覽器中,通過代碼控制與頁面上元素進行交互,並獲取對應的信息。
以前我們我們爬取數據都是通過寫代碼爬取,當待爬取的網站需要登錄時,我們需要在代碼中模擬登錄;當爬取過快需要驗證時,我們需要在代碼中實現驗證邏輯;當ip被封時,還需要有自己的動態ip庫。待爬網站的反爬策略越多,我們爬取的成本就越大。總之,用寫代碼的方式爬取數據需要構造比較復雜的請求,想盡一切辦法將爬蟲偽裝成真實的用戶。
使用pyppeteer
這樣的工具,就可以在很大程度上解決上面的問題。同時,還有一個優點是所見即所得,不需要再去研究網頁復雜的請求結構。當然這類工具也是優缺點的,它增加了你去理解網頁上各種元素以及交互的成本。所以我覺得這類工具最適合在短平快的爬蟲場景中使用。比如我在最近的工作中就遇到兩次這樣的情況,想爬一些特別簡單的數據來提升工作效率,但又不想研究網頁是如何構造請求的,用這種所見即所得的工具就可以快速抓取想要的數據。
下面我們以“抓取百度搜索數據”例子我介紹一下pyppeteer
的使用。正式介紹前我們先來看下爬取效果:
安裝pyppeteer
python3 -m pip install pyppeteer
安裝完成后,執行pyppeteer-install
命令安裝最新版本的 Chromium 瀏覽器。根據官方文檔的說明,安裝pyppeteer
需要Python
3.6以上的版本。
由於pyppeteer
是基於asyncio
實現的,所以我們的代碼中也會用async/await來寫代碼,之前沒寫過的朋友也不用擔心,基本不影響對pyppeteer
的使用,有必要的話以后再單獨寫篇文章介紹。
首先,用pyppeteer
啟動 chrome 進程
from pyppeteer import launch
# headless 顯示瀏覽器 # --window-size 設置窗體大小 browser = await launch({'headless': False, 'args': ['--window-size=%d,%d' % (width, height)] })
然后,打開一個新的標簽,並訪問百度
# 打開新頁面
page = await browser.newPage() # 設置內容顯示大小 await page.setViewport({"width": width, "height": height}) # 訪問百度 await page.goto('https://www.baidu.com')
打開百度網站后,下一步就要向搜索輸入框輸入內容,首先要找到輸入框的html標簽 從上圖可以看到,
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
代碼代表搜索輸入框,該標簽的 class 是s_ipt
,那下面我們就通過type
函數找到該標簽,並鍵入需要搜索的內容
# 將對應的 selector 填入 python,通過.s_ipt找到輸入框html標簽
await page.type('.s_ipt', 'python')
這里我們搜的是python,有了輸入后就可以點擊“百度一下”按鈕來發起搜索。找按鈕的方式與上面一樣 可以看到
<input type="submit" id="su" value="百度一下" class="bg s_btn">
代碼代表“百度一下”的按鈕,該標簽的 id 是su
,下面就調用click
函數找到該標簽,並點擊
# 通過#su找到“百度一下”按鈕html標簽
await page.click('#su')
這里需要注意su
前面是#
而不是.
,因為在html標簽中它用id
表示而不是class
,這里涉及html selector的內容,不清楚的朋友可以簡單補一下。
執行完上面的代碼,我們可以看到搜索結果了,調用screenshot
方法將當前頁面保存
await page.screenshot({'path': 'example.png'})
效果如下: 接下來我們就獲取網頁內容,並解析每條結果
# 獲取網頁內容
content = await page.content() # 解析 output_search_result(content)
通過BeatifulSoup
解析每條結果的標題與鏈接
def output_search_result(html):
search_bs = BeautifulSoup(html, 'lxml') all_result = search_bs.find_all("div", {'class': "result c-container"}) for single_res in all_result: title_bs = single_res.find("a") title_url = title_bs.get('href') title_txt = title_bs.get_text() print(title_txt, title_url)
輸出的內容如下
python官方網站 - Welcome to Python.org http://www.baidu.com/link?url=OqtoElo8HW1GdOgAlqdCTz2lpewFLf0HlbnGdyAKD06BfPbw0fsJ_N5fclxx-q1D
Python 基礎教程 | 菜鳥教程 http://www.baidu.com/link?url=IooFgJjdec1qPXhGhF7tur-z2Qt_43RkK3L-9cp8oB-0i2w7unKzLayLjg3zSQeKQieA49JFejMjqTM-TSY3V_ Python3 * 和 ** 運算符_python_極客點兒-CSDN博客 http://www.baidu.com/link?url=H3VdAQRAbTkN9jGJGkvhIFTdg48O-b5yib7vCquWyg1-6FZwBVHnJ5iiUYQkjbf-8IuLfOwDXoUMDOdMvXNHkzejts4uRHrczgQqekgQuFy Python教程 - 廖雪峰的官方網站 http://www.baidu.com/link?url=piu0nEfXNvkLhWchcdX2EjJvIkQ5beq2_uYH_B7u2vjYO82BZwr8SXgDxnVLZYgGL8xuR_ovjg2cAYfPS9AmLtqUQP-TrWuJWHNqYbxdQnUPTy_VPp8sSBdCaYBl9YDX Python3 教程 | 菜鳥教程 http://www.baidu.com/link?url=bx1rMrzxC69Sp0zY08-VhFs40QQ8UFxZdvmZVFcKYkCG2mdojhAMjk5ulKBKwQm77x8vMyOeowW_bNtoP35m3q 你都用 Python 來做什么? - 知乎 http://www.baidu.com/link?url=YTMr1ycFjtkWx8lgJ_PT3-kF50vYI6Yibh4o69WL_afBSOkkZmGxexxIKXY3fGAX8X2-AaFbI4jL1vJbKMJrsK Python基礎教程,Python入門教程(非常詳細) http://www.baidu.com/link?url=elAepKY7rhULzTPuwKvk8Cxx21K5D0Ey7-Wj9TZgN49MyasPOXtLYfWbp46QZQie
這樣,我們的抓取數據的目的已經達到了,當然我們還可以繼續拓展下,多用用pyppeteer
,比如:我們可以點擊下一頁,抓取下一頁的內容
# next page
# 為了點擊“下一頁”,需要將當前頁面滑到底部 dimensions = await page.evaluate('window.scrollTo(0, window.innerHeight)') # 點擊“下一頁”按鈕 await page.click('.n') # 獲取第二頁的內容 content = await page.content() # 解析 output_search_result(content)
操作與之前類似,注釋寫的也比較清楚,我就不再贅述了。最后可以調用await browser.close()
代碼關閉瀏覽器。上述代碼可以定義需要定義在一個async
函數中,如:
async def main():
# ... 抓取代碼
然后通過下面代碼
asyncio.get_event_loop().run_until_complete(main())
調用main
函數。
pyppeteer
的用法就介紹到這里了,類似的工具還有很多,比如:Selenium,我也試了下,確實如網上所說配置上面需要花些功夫,有興趣的朋友可以自行嘗試。希望今天的內容對你有用。關注公眾號回復關鍵字 爬蟲 獲取完整源碼
歡迎公眾號「渡碼」,輸出別地兒看不到的干貨。
