python爬蟲-翻頁url不變網頁的爬蟲探究
url隨着翻頁改變的爬蟲已經有很是多教程啦,這裏主要記錄一下我對翻頁url不變網頁的探究過程。
學術菜雞第一次寫CSDN,請你們多多包容~ 若是對你有一點點幫助,請幫我點個贊吧!
html
翻頁url不變 與 翻頁url改變 有什麼區別?
url其實就是連接,翻頁url改變的連接就是翻頁請求在url中體現的連接,比方說不少爬蟲初學者的第一個爬蟲實例:爬取豆瓣電影top250的信息。python
注意看這個網站的連接!!
這裏能夠看到控制頁數的參數start直接在url中體現了,改變start=以後的數值就可以實現翻頁。start=25對應的頁面就是從26開始的電影,start=0對應的頁面就是從1開始的電影。那麼只須要控制start以後的數字以25爲步長遞增就能夠經過for函數實現翻頁。
web
可是有時候會遇到明明你點擊了翻頁,但url卻不改變的狀況,好比這個:
這種狀況沒有辦法在python中直接經過改變url實現翻頁。
json
找到翻頁命令
事實上,控制網頁翻頁總得有一個參數,只是在翻頁url改變的狀況中,這個翻頁參數體如今了url中,這使得咱們能夠經過直接改變url的方式實現翻頁。對於翻頁url不變的狀況,咱們其實只須要找到翻頁命令所在的位置,而後控制這條命令便可。服務器
下面介紹我找到翻頁命令的一種方式:app
- 打開開發者模式
- 在打開開發者模式的狀況下點擊翻頁
- 找到翻頁後返回的內容表單 (通常是XHR格式)
- 查看其headers (注意pages,start,p等字眼)
- 提取相應的部分,在python中編寫語句實現控制就能夠控制翻頁了
爬取去哪兒酒店信息實例
-
打開開發者模式,並點擊翻頁
python爬蟲 -
找到返回的第二頁內容的表單
能夠點擊list-preview打開表單預覽,確認這個list確實是服務器返回的第二頁酒店內容
這裏能夠看到list裏面的內容確實就是第二頁的酒店內容,那麼咱們就要尋找這個list是怎麼返回的,即它是經過向服務器發送什麼命令返回的!!
函數 -
查看list的headersoop
能夠發如今Request Headers之下多了一個新的模塊,叫作Request Payload
(我以前在CSDN上看到不少帖子,都是講From Data或者Query String Parameters,可是我卻一直沒找到這兩個模塊,只有Request Payload,後來通過高人指點才知道,其實在Request Payload內也有可能隱藏着翻頁的信息,因此我在想不必定要侷限在具體的模塊名字,關鍵是找到翻頁以後服務器返回的信息表單,找它的headers有什麼與第一頁headers不一樣的地方)
post
- 將Request Payload的內容打開觀察
觀察Request Payload裏的內容,發現這條指令實際上是向服務器發送了一些要求,好比說要求了須要查找的酒店所在城市是西安,還指定了查詢的日期。能夠看到這裏有一條start:20的命令,通過對比第一頁list的同一位置(start:0)發現start:i就是控制返回不一樣頁面的命令。
至此咱們已經發掘到了翻頁url不變網站的翻頁命令,下面只須要在爬蟲構造headers的時候,加上Request Payload裏要求的內容,其中start控制內容由函數參數控制。這樣就實現了控制爬取頁數的操做。
除此以外,不難發現咱們甚至還能夠控制經過控制Request Payload中的city方便地實現對不一樣城市酒店的爬取。
代碼
下面附上完整代碼,因爲去哪兒網頁時常加載失敗,因此若是前兩次出現「No targets found」頗有多是因爲連接網頁失敗,多試幾回就行了。
- 經過修改main()裏的city,能夠爬取不一樣城市的酒店信息。
- 經過修改getlist()裏z的範圍,能夠改變爬取頁數。
- 我沒有對正則提取的內容作任何模糊處理,理論上覆制這個代碼就能夠運行。
- 大多數城市直接輸入城市拼音就能夠爬到(連接失敗就多試幾回),可是北京得用beijing_city。若是有的城市試了不少次都連接失敗,能夠上去哪兒網手動搜索看看url裏的city是怎樣的,手動添加一下就能夠了。
#-*- codeing = utf-8 -*- #@Time : 2020/8/4 9:25 上午 #@Author : Tango #@File : hotel_general.py #@Software : PyCharm import time import re import requests from bs4 import BeautifulSoup import xlwt import json findname = re.compile(r'<a class="hotel-name".*>(.*?)</a>') findgrade = re.compile(r'<span class="num">(3|4|("4))\.(.*?)</span><span class="desc">') findtotal = re.compile(r'<span class="total">共(.*)條評論</span>') findprice = re.compile(r'<span class="y rmb">¥</span>(.*)<span class="qi">起</span>') finddetail = re.compile(r'<a class="btn hotel-card-detail-btn" (.*?)" rel="noopener noreferrer" target="_blank" title=.*>查看詳情</a>') def askurl(city, i, url): #獲取網頁內容(post) request_payload = { "b": "{bizVersion: \"17\", cityUrl:" + city + ", cityName: \"\", fromDate: \"2020-08-04\", toDate: \"2020-08-05\", q: \"\",…}", "bizVersion": "17", "channelId": 1, "cityName": "", "cityType": 1, "cityUrl": city, "comprehensiveFilter": [], "fromAction": "", "fromDate": "2020-08-04", "fromForLog": 1, "hourlyRoom": "false", "level": "", "locationAreaFilter": [], "maxPrice": -1, "minPrice": 0, "num": 20, "q": "", "qFrom": 3, "searchType": 0, "sort": 0, "start": int(i*20), "toDate": "2020-08-05", "userId": "", "userName": "", "uuid": "", "qrt": "h_hlist", "source": "website" } head = { "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36" } response = requests.post(url, headers=head, data=json.dumps(request_payload)) #headers裏表示這裏的數據獲取是post方法,因此使用requests.post函數 return response.text def getlist(city, url): hotellist = [] for z in range(0, 3): # 爬取頁數設置 page = askurl(city, z, url) #爬取第z頁 soup = BeautifulSoup(page, 'html.parser') #是一個樹形結構了 lsts = soup.find_all('div', class_="inner clearfix" ) ##表空判斷 if not lsts: print("No targets found") print("鏈接到網頁失敗") exit(0) print("連接網頁成功,開始爬取數據") number = 1 #非空狀況下讀取 for item in lsts: hotel = [] #每一個hotel存放一個酒店的信息(列表形式) item = str(item) # 酒店名稱 hotel_name = re.findall(findname, item)[0] hotel.append(hotel_name) # 酒店評分 hotel_grade = re.findall(findgrade, item) temp = list(hotel_grade) if temp: hotel.append(temp[0][0]) hotel.append(temp[0][2]) else: hotel.append(0) hotel.append(0) # 酒店總評分數 hotel_total = re.findall(findtotal, item)[0] hotel.append(hotel_total) # 酒店起步價 hotel_price = re.findall(findprice, item) if len(hotel_price): hotel_price = hotel_price[0] else: hotel_price = 0 hotel.append(hotel_price) # 詳情連接 hotel_info = re.findall(finddetail, item)[0] hotel.append(hotel_info) # 寫入hotellist hotellist.append(hotel) print("-----正在爬取第%d條酒店信息-----"%number) number += 1 time.sleep(1.5) time.sleep(7.5) print("第%d頁爬取完成"%(z+1)) return hotellist def listToExcel(city, list): col = ['酒店名稱', '酒店評分整數', '酒店評分小數', '酒店評價總數', '起步價', '詳情網址'] hotelbook = xlwt.Workbook(encoding = "utf-8", style_compression = 0) hotelsheet = hotelbook.add_sheet("sheet1", cell_overwrite_ok = True) for i in range(len(col)): hotelsheet.write(0, i, col[i]) for i in range(0,len(list)): print("-----正在寫入第%d條酒店信息-----"%(i+1)) item = list[i] for j in range(len(col)): hotelsheet.write(i+1, j, item[j]) hotelbook.save(city + "hotel.xls") def main(): city = "beijing_city" #基本上寫入城市拼音便可,可是北京要寫成beijing_city baseurl = "https://hotel.qunar.com/city/" + city + "/#fromDate=2020-01-01&cityurl=xiamen&toDate=2020-01-02&from=qunarHotel" hotellist = getlist(city, baseurl) listToExcel(city, hotellist) #askurl(baseurl) if __name__ == '__main__': main()