python爬蟲 - 翻頁url不變網頁的爬蟲探究

python爬蟲-翻頁url不變網頁的爬蟲探究

url隨着翻頁改變的爬蟲已經有很是多教程啦,這裏主要記錄一下我對翻頁url不變網頁的探究過程。
學術菜雞第一次寫CSDN,請你們多多包容~ 若是對你有一點點幫助,請幫我點個贊吧!
html

翻頁url不變 與 翻頁url改變 有什麼區別?

url其實就是連接,翻頁url改變的連接就是翻頁請求在url中體現的連接,比方說不少爬蟲初學者的第一個爬蟲實例:爬取豆瓣電影top250的信息。python

注意看這個網站的連接!!
豆瓣電影url實例
這裏能夠看到控制頁數的參數start直接在url中體現了,改變start=以後的數值就可以實現翻頁。start=25對應的頁面就是從26開始的電影,start=0對應的頁面就是從1開始的電影。那麼只須要控制start以後的數字以25爲步長遞增就能夠經過for函數實現翻頁。

web

可是有時候會遇到明明你點擊了翻頁,但url卻不改變的狀況,好比這個:
url不變示例
這種狀況沒有辦法在python中直接經過改變url實現翻頁。

json

找到翻頁命令

事實上,控制網頁翻頁總得有一個參數,只是在翻頁url改變的狀況中,這個翻頁參數體如今了url中,這使得咱們能夠經過直接改變url的方式實現翻頁。對於翻頁url不變的狀況,咱們其實只須要找到翻頁命令所在的位置,而後控制這條命令便可。服務器

下面介紹我找到翻頁命令的一種方式:app

  1. 打開開發者模式
  2. 在打開開發者模式的狀況下點擊翻頁
  3. 找到翻頁後返回的內容表單 (通常是XHR格式)
  4. 查看其headers (注意pages,start,p等字眼)
  5. 提取相應的部分,在python中編寫語句實現控制就能夠控制翻頁了

爬取去哪兒酒店信息實例

  • 打開開發者模式,並點擊翻頁
    翻頁
    python爬蟲

  • 找到返回的第二頁內容的表單
    list
    能夠點擊list-preview打開表單預覽,確認這個list確實是服務器返回的第二頁酒店內容
    確認表單
    這裏能夠看到list裏面的內容確實就是第二頁的酒店內容,那麼咱們就要尋找這個list是怎麼返回的,即它是經過向服務器發送什麼命令返回的!!



    函數

  • 查看list的headersoop

list的headers

能夠發如今Request Headers之下多了一個新的模塊,叫作Request Payload
(我以前在CSDN上看到不少帖子,都是講From Data或者Query String Parameters,可是我卻一直沒找到這兩個模塊,只有Request Payload,後來通過高人指點才知道,其實在Request Payload內也有可能隱藏着翻頁的信息,因此我在想不必定要侷限在具體的模塊名字,關鍵是找到翻頁以後服務器返回的信息表單,找它的headers有什麼與第一頁headers不一樣的地方
post

  • 將Request Payload的內容打開觀察
    key!!!
    觀察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()

最後,特別要感謝Zenith和Jonty的幫助和討論,耶~

相關文章
相關標籤/搜索