Ajax,是利用JavaScript在保證頁面不被刷新,頁面鏈接不改變的情況下與服務器交換數據並更新部分網頁的技術。簡單的說,Ajax使得網頁無需刷新即可更新其內容。舉個例子,我們用瀏覽器打開新浪微博,進入某個用戶的頁面,當我們瀏覽到該頁末尾時,會出現一個加載的動畫,然后就刷新出來的新的微博內容,這個過程並不需要我們手動的刷新網頁。
Ajax的原理:發送Ajax請求到網頁更新的這個過程可分為三步:
1.發送請求
2.解析內容
3.渲染網頁
詳細的原理介紹可參照:https://www.cnblogs.com/wanghp/p/6991554.html
簡單的說,JavaScript新建了一個XMLHttpRequest對象,然后調用onreadystatechange屬性設置了監聽,然后調用open()方法和send()方法向服務器發送了請求,當服務器返回響應時,監聽對應的方法便會觸發,然后在方法里解析響應的內容,從而實現了無需刷新便能更新網頁。
那么如何查看Ajax請求呢?以爬取嗶哩嗶哩番劇索引追番人數排行為例,我們使用Chrome瀏覽器打開https://www.bilibili.com/anime/index/#season_version=-1&area=-1&is_finish=-1©right=-1&season_status=-1&season_month=-1&pub_date=-1&style_id=-1&order=3&st=1&sort=0&page=1,並按F12打開開發者工具,如圖所示:
在開發者工具中切換到Network選項卡,然后重新刷新頁面,篩選XHR請求類型,如圖所示:
在左邊找到我們需要爬取的Ajax請求,即
點擊header可以查看該請求的header信息,之后我們會用到。
Preview是該請求返回的響應內容,包含了我們所要爬取的信息。
接下來我們以爬取b站追番人數排行榜為例來介紹如何提取Ajax結果:
首先在header中找到請求鏈接,即Request URL:
接着找到該請求的參數信息:
觀察到每次翻頁,page參數+1,其他參數沒有改變,所以我們每次請求時只需要改變page參數即可。
下面給出代碼示例:
1 from urllib.parse import urlencode 2 import requests 3 import time 4 import csv 5 import os 6 7 base_url = "https://bangumi.bilibili.com/media/web_api/search/result?" 8 9 headers = { 10 'Host':'bangumi.bilibili.com', 11 'Referer':'https://www.bilibili.com/anime/index/', 12 'User_Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36', 13 'Origin': 'https://www.bilibili.com', 14 } 15 16 def get_page(page): 17 #參數 18 params = { 19 'season_version':'-1', 20 'area': '-1', 21 'is_finish': '-1', 22 'copyright': '-1', 23 'season_status': '-1', 24 'season_month':'-1', 25 'pub_date': '-1', 26 'style_id': '-1', 27 'order': '3', 28 'st': '1', 29 'sort': '0', 30 'page': page, 31 'season_type':'1', 32 'pagesize':'20' 33 } 34 url = base_url + urlencode(params) 35 try: 36 response = requests.get(url,headers=headers,allow_redirects=False) 37 #將內容解析為json格式返回 38 return response.json() 39 except requests.ConnectionError as e: 40 print('Error',e.args) 41 42 def parse_page(json): 43 if json: 44 items = json.get('result').get('data') 45 for item in items: 46 ret = {} 47 ret['title'] = item.get('order').get('title') 48 ret['score'] = item.get('order').get('score') 49 ret['play'] = item.get('order').get('play') 50 ret['follow'] = item.get('order').get('follow') 51 ret['index_show'] = item.get('index_show') 52 ret['is_finish'] = item.get('is_finish') 53 yield item 54 55 #寫入文件 56 def write_to_file(items): 57 with open("bilibili.csv","a+") as csvfile: 58 writer = csv.writer(csvfile) 59 for item in items: 60 print(item) 61 writer.writerow([item['order']['follow'],item['title'],item['order']['score'], 62 item['order']['play'],item['index_show'],item['is_finish']]) 63 64 65 def main(offset): 66 json = get_page(offset) 67 results = parse_page(json) 68 write_to_file(results) 69 return 0 70 71 72 if __name__ == '__main__': 73 for page in range(1,11): 74 main(offset=page) 75 time.sleep(1) 76 77
運行結果: