前言
這次我們爬取一個資料量相對大一點的網站,網站連結為:https://spa5.scrape.center/如下圖所示:
這是一個圖書網站,整個網站有數千本圖書資訊,網站資料是JavaScript渲染得到,資料可以通過 Ajax 接口擷取,由于這個網站資料量比較多,是以更加适合做異步爬取。
我們需要用aiohttp爬取全站的圖書資料,并且将資料通過異步的方式儲存到MongoDB中。
爬取過程
頁面分析
這個網站的資料是通過Aiax加載的,根據之前分析Aiax的案例,可以輕松得到如下信
息:
1、清單頁的Ajax請求接口格式為:
https://spa5.scrape.center/api/book?limit=18&offset={offset};
2、在清單頁Ajax接口傳回的資料裡,results 字段包含目前頁裡18本圖書資訊,其中每本的資料中都含有一個id字段,這個id就是圖書本身的id,可以用來進一步請求詳情頁;
3、詳情頁的 Ajax 請求接口格式為: https://spa5.scrape.center/api/book/{id},
其中id即為詳情頁對應圖書的id。
實作思路
一個完善的異步爬蟲應該充分利用資源進行全速爬取,其實實作思路是維護一個動态變化的爬取隊列,每産生一個新的task,就将其放入爬取隊列中,專門的爬蟲消費者從此隊列中擷取task并執行,能做到在最大并發量的前提下充分利用等待時間進行額外的爬取隊列。
本次實戰主要是利用aiohttp進行異步爬取,我們這裡将爬取邏輯拆分為兩個部分,第一部分為爬取清單頁,第二部分為爬取詳情頁,這兩個部分串行執行,最後将爬取結果以異步的方式儲存在 MongoDB 裡面。
爬取清單頁
先聲明一個信号量來控制最大并發數量,再定義一個通用的爬取方法,方法名為: scrape_api,該方法用async修飾,在裡面使用async with語句引入信号量作為上下文,接
着調用session的get方法請求這個url,再定義一個方法scrape_index來爬取清單頁,如下所:
接着定義一個 main 方法,将上面的方法串聯起來,實作如下:
這裡首先聲明了session對象,即最初聲明的全局變量,這樣的話,就不需要再各個方法裡面都傳遞session了,接着定義scrape_index_tasks,這就是用于爬取清單頁所有task組成的清單,然後調用asyncio 的gather 方法,并将 task 清單傳入其參數。最後調用main方法,使用時間循環啟動該 main 方法對應的協程即可。
爬取詳情頁
第二階段是爬取詳情頁并儲存資料,由于每個詳情頁分别對應一本書,每本書都需要一個ID作為唯一辨別,是以我們需要将所有詳情頁的ID擷取出來。在main方法裡面增加results的解析代碼,如下所示:
下面就是儲存資料,這裡我們需要用支援異步的MongoDB存儲庫motor,具體代碼如下:
最後在在main方法裡面增加對詳情頁的提取和儲存資料即可。
運作腳本,可以看到爬取成功,并成功存儲資料,沒有任何報錯資訊。