python爬虫学习笔记分析Ajax爬取果壳网文章
有時在使用requests抓取頁面會遇到得到的結果與在瀏覽器 中看到的結果不一樣,在瀏覽器檢查元素中可以看到的正常的顯示的網頁數據,但是requests請求得到的結果卻沒有。這是因為requests請求得到的時原始的html文檔,而瀏覽器中的界面確實經過JavaScript處理數據生成的結果,這些數據來源可能不同,有的時Ajax加載的,可能包含在html文檔中,也有可能經過JavaScript渲染得到的。
對于Ajax(全稱:Asynchronous JavaScript and XML),即異步的JavaScript和XML,是一種利用JavaScript技術在保證頁面不刷新的情況下與服務器交換數據并更新部分網頁的技術。
對于沒有使用Ajax技術的網頁來說,要想更新內容,就必須刷新整個頁面,但使用Ajax就可以在后臺完成與服務器的數據交互,獲取到數據之后,再利用JavaScript改變網頁即可。
這里以果殼網科學人為例,url為:“https://www.guokr.com/scientific/”,在文章下拉中我們并沒有發現有翻頁的操作,但會出現一個加載動畫,然后下方又出現了新的內容,這個過程就是Ajax加載的過程,而網頁的連接并沒有改變。
Ajax加載動畫
Ajax的分析:
Ajax具體又是如何實現這一過程的呢。從發送Ajax請求到網頁更新過程中其實可以簡單分為一下3個部分:
1)發送請求;
2)解析內容;
3)渲染網頁
這個過程基本都需要以來JavaScript來實現,因為不是專業的,這里就不班門弄斧了,下面具體來說一下分析方法;
以chrome瀏覽器來介紹,打開鏈接:“https://www.guokr.com/scientific/”,打開開發者工具,并切換到network選項卡,如下圖所示:
network面板結果
這里可以看到非常多的條目,但Ajax的請求是一種特殊的類型,叫做xhr,在選項欄直接選區XHR,則剩下顯示的就都是Ajax請求了,并且隨著下滑在下方會不斷的出現新的Ajax請求,下面就可以通過分析這個請求去實現數據的爬取了。(在請求頭信息中發現X-Requested-With: XMLHttpRequest字段即為Ajax請求)
選定其中一個請求,進入詳情界面,如下圖:
可以發現這是一個GET類型的請求,請求的鏈接為:’https://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset=38&_=1545367819629‘,請求的參數有3個:retrieve_type,limit和offset,通過查看其他請求發現retrieve_type,limit始終如一,改變的只有offset值,即控制分頁的參數,且規律很簡單,第一頁為18,此后每一頁增加20.
接下來觀察這個請求的響應內容,即preview界面,如下圖:
響應內容
可以發現這個響應內容是JSON格式的,瀏覽器幫我們做了解析,可以看到信息就是在result里面,這里我們只需要得到文章的鏈接即可,即url字段,然后在每一個詳情頁面對文章內容解析。
接下來是具體代碼的實現:
首先定義一個方法來獲取每次請求的結果,在請求時,將offset作為參數傳入來構造url,代碼如下:
定義了base_url來實現url前半部分,構造data字典,使用urlencode()方法將參數轉換為GET請求參數,實現url的拼接,使用requests的get()方法請求鏈接,判斷狀態碼為200后,返回json格式的結果。
下面定義一個方法去解析出每篇文章對應的鏈接:
在返回的內容中得到result,然后遍歷它得到文章的url。
通過得到的文章鏈接欸,然后就可以在新頁面解析得到文章具體內容,這里我們獲取文章標題,作者以及正文,代碼如下:
這里使用BeautifulSoup來解析html,返回了title,autor以及article字段,其中去除標簽的方法可以借用pyquery庫的text()方法來實現。
最后時文章的保存,我們選擇保存為txt文本格式,每一篇文章為一個文件,以獲取的title字段命名即可,代碼如下:
def save_article(content):try:if content.get('title'):filename=str(content.get('title'))+'.txt'with open(file_name, 'w',encoding='utf-8') as f:#f.write(json.dumps(content,ensure_ascii=False))f.write('\n'.join([str(content.get('title')),str(content.get('autor')),str(content.get('article'))]))print('Downloaded article path is %s' % filename)else:print('Already Downloaded', file_path)except requests.ConnectionError:print('Failed to Save Image,item %s' % content)這樣就實現了獲取文章的保存,效果如下圖:
當然我們也可以將其保存到mongodb數據庫中,代碼如下:
最后通過傳入offset來實現翻頁爬取,代碼如下:
import time def main(offset):result=get_index(offset)all_url=get_url(result)for url in all_url:article=get_text(url)for art in article:#print(art)save_article(art)GROUP_START = 0 GROUP_END = 10if __name__ == '__main__':for i in range(GROUP_START,GROUP_END+1):main(offset=i*20+18)time.sleep(1)這樣雖然也可以實現功能,但因為還是一個進程,會導致速度很慢,這里我們選擇使用進程池的方法,將代碼可以修改為:
GROUP_START = 0 GROUP_END = 10 from multiprocessing.pool import Pool if __name__ == '__main__':pool=Pool()pool.map(main,[x*20+18 for x in range(GROUP_START,GROUP_END+1)])time.sleep(1)這里通過GROUP_START,GROUP_END兩個參數來控制爬取的頁數.因為沒有使用代理,這里加入一個休眠時間防止請求過于頻繁。
這樣就實現了Ajax加載頁面的數據爬取,初步做到了可見即可爬的設想。
ps:github地址如下:‘https://github.com/linl12138/Ajax_guoke’
總結
以上是生活随笔為你收集整理的python爬虫学习笔记分析Ajax爬取果壳网文章的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 因为计算机丢失D3DCOMPILER_4
- 下一篇: 虚继承是什么意思_程序猿是什么意思?程序