python爬虫 - 翻页url不变网页的爬虫探究(转载)

python爬虫-翻页url不变网页的爬虫探究
url随着翻页改变的爬虫已经有非常多教程啦,这里主要记录一下我对翻页url不变网页的探究过程。
学术菜鸡第一次写CSDN,请大家多多包容~ 如果对你有一点点帮助,请帮我点个赞吧!

翻页url不变 与 翻页url改变 有什么区别?
url其实就是链接,翻页url改变的链接就是翻页请求在url中体现的链接,比方说很多爬虫初学者的第一个爬虫实例:爬取豆瓣电影top250的信息。

注意看这个网站的链接!!
豆瓣电影url实例
这里可以看到控制页数的参数start直接在url中体现了,改变start=之后的数值就能够实现翻页。start=25对应的页面就是从26开始的电影,start=0对应的页面就是从1开始的电影。那么只需要控制start之后的数字以25为步长递增就可以通过for函数实现翻页。

但是有时候会遇到明明你点击了翻页,但url却不改变的情况,比如这个:
url不变示例
这种情况没有办法在python中直接通过改变url实现翻页。

找到翻页命令
事实上,控制网页翻页总得有一个参数,只是在翻页url改变的情况中,这个翻页参数体现在了url中,这使得我们可以通过直接改变url的方式实现翻页。对于翻页url不变的情况,我们其实只需要找到翻页命令所在的位置,然后控制这条命令即可。

下面介绍我找到翻页命令的一种方式:

打开开发者模式
在打开开发者模式的情况下点击翻页
找到翻页后返回的内容表单 (一般是XHR格式)
查看其headers (注意pages,start,p等字眼)
提取相应的部分,在python中编写语句实现控制就可以控制翻页了
爬取去哪儿酒店信息实例
打开开发者模式,并点击翻页
翻页

找到返回的第二页内容的表单
list
可以点击list-preview打开表单预览,确认这个list确实是服务器返回的第二页酒店内容
确认表单
这里可以看到list里面的内容确实就是第二页的酒店内容,那么我们就要寻找这个list是怎么返回的,即它是通过向服务器发送什么命令返回的!!

查看list的headers

list的headers

可以发现在Request Headers之下多了一个新的模块,叫做Request Payload
(我之前在CSDN上看到很多帖子,都是讲From Data或者Query String Parameters,但是我却一直没找到这两个模块,只有Request Payload,后来经过高人指点才知道,其实在Request Payload内也有可能隐藏着翻页的信息,所以我在想不一定要局限在具体的模块名字,关键是找到翻页之后服务器返回的信息表单,找它的headers有什么与第一页headers不同的地方)

将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”.>(.?)’)
findgrade = re.compile(r’(3|4|(“4)).(.?)’)
findtotal = re.compile(r’共(.)条评论’)
findprice = re.compile(r’¥(.)’)
finddetail = re.compile(r’<a class=“btn hotel-card-detail-btn” (.
?)” rel=“noopener noreferrer” target="_blank" title=.*>查看详情’)

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的帮助和讨论,耶~

原文链接:https://blog.csdn.net/tangogoooooo/article/details/107788757?utm_medium=distribute.pc_feed.none-task-blog-cf-3.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-cf-3.nonecase&request_id=5f2b1df02405af26f814df89

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值