分享一個零基礎快速爬取數據的工具

今天介紹下如何使用pyppeteer抓取網頁的數據。pyppeteer是web應用自動化測試的具,可以直接運行在瀏覽器中,通過程式碼控制與頁面上元素進行交互,並獲取對應的資訊。

以前我們我們爬取數據都是通過寫程式碼爬取,當待爬取的網站需要登錄時,我們需要在程式碼中模擬登錄;當爬取過快需要驗證時,我們需要在程式碼中實現驗證邏輯;當ip被封時,還需要有自己的動態ip庫。待爬網站的反爬策略越多,我們爬取的成本就越大。總之,用寫程式碼的方式爬取數據需要構造比較複雜的請求,想盡一切辦法將爬蟲偽裝成真實的用戶。

使用pyppeteer這樣的工具,就可以在很大程度上解決上面的問題。同時,還有一個優點是所見即所得,不需要再去研究網頁複雜的請求結構。當然這類工具也是優缺點的,它增加了你去理解網頁上各種元素以及交互的成本。所以我覺得這類工具最適合在短平快的爬蟲場景中使用。比如我在最近的工作中就遇到兩次這樣的情況,想爬一些特別簡單的數據來提升工作效率,但又不想研究網頁是如何構造請求的,用這種所見即所得的工具就可以快速抓取想要的數據。

下面我們以「抓取百度搜索數據」例子我介紹一下pyppeteer的使用。正式介紹前我們先來看下爬取效果:

安裝pyppeteer

python3 -m pip install pyppeteer

安裝完成後,執行pyppeteer-install命令安裝最新版本的 Chromium 瀏覽器。根據官方文檔的說明,安裝pyppeteer需要Python3.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('//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 //www.baidu.com/link?url=OqtoElo8HW1GdOgAlqdCTz2lpewFLf0HlbnGdyAKD06BfPbw0fsJ_N5fclxx-q1D
Python 基礎教程 | 菜鳥教程 //www.baidu.com/link?url=IooFgJjdec1qPXhGhF7tur-z2Qt_43RkK3L-9cp8oB-0i2w7unKzLayLjg3zSQeKQieA49JFejMjqTM-TSY3V_
Python3 * 和 ** 運算符_python_極客點兒-CSDN部落格 //www.baidu.com/link?url=H3VdAQRAbTkN9jGJGkvhIFTdg48O-b5yib7vCquWyg1-6FZwBVHnJ5iiUYQkjbf-8IuLfOwDXoUMDOdMvXNHkzejts4uRHrczgQqekgQuFy
Python教程 - 廖雪峰的官方網站 //www.baidu.com/link?url=piu0nEfXNvkLhWchcdX2EjJvIkQ5beq2_uYH_B7u2vjYO82BZwr8SXgDxnVLZYgGL8xuR_ovjg2cAYfPS9AmLtqUQP-TrWuJWHNqYbxdQnUPTy_VPp8sSBdCaYBl9YDX
Python3 教程 | 菜鳥教程 //www.baidu.com/link?url=bx1rMrzxC69Sp0zY08-VhFs40QQ8UFxZdvmZVFcKYkCG2mdojhAMjk5ulKBKwQm77x8vMyOeowW_bNtoP35m3q
你都用 Python 來做什麼? - 知乎 //www.baidu.com/link?url=YTMr1ycFjtkWx8lgJ_PT3-kF50vYI6Yibh4o69WL_afBSOkkZmGxexxIKXY3fGAX8X2-AaFbI4jL1vJbKMJrsK
Python基礎教程,Python入門教程(非常詳細) //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,我也試了下,確實如網上所說配置上面需要花些功夫,有興趣的朋友可以自行嘗試。希望今天的內容對你有用。

歡迎公眾號「渡碼」,輸出別地兒看不到的乾貨。


Tags: