Python-爬取携程景点信息
携程在⼿ 说⾛就⾛。今天来记录⼀下爬取携程旅⾏的教程。
⾸先告诉⼤家,爬携程还是相对简单的,当然也有难得⽅法,这⾥就以实现为最终⽬标讲解最简单得⽅法。
我要采集得是携程门票⼀栏得景点信息。还是照惯例⽤chrome抓包。⾸先需要获取每个景点详情页的url,我这边到了直接贴图。
原来以为拿到这个页⾯问题就解决了,可实践发现事情并没有我想的那么简单,这是⼀个post请求。我把参数都带上进⾏访问,压根拿不到数据。返回的json⽂件是这样的。
研究了⼀下,发现参数⾥有⼀个变动的加密参数‘traceid’,很明显每次请求都会⽣成⼀个⼀次性的加密参
数,⼀次之后就过期⽆法复⽤,如果要⾛这个⽅法只能去做js逆向解密破解它,然⽽我内⼼是拒绝的,这不符合我的⼈物设定。
也给看到⽂章的朋友讲讲,如果你不是专注只做爬⾍的话,其实没必要去研究js解密,因为⾸先你得会js。爬⾍这个⽅向说实话⼊门的下限很低,但是上限⾮常⾼。如果你⼀⼼只搞爬⾍,那可以花⼤把时间去研究,像我这种只拿爬⾍作为⼯具的就不想花太多时间在这上⾯了。所以这⾥我改⽤selenium去获取数据,简单实⽤太⾹了。
selenium功能还是挺强⼤的,使⽤这个⽅法就可以拿到class值为’right-content-list’标签下的所有内容。然后就是正则匹配出每个景点详情页的url以及标题。拿到详情页的标题之后就可以requests请求详情页数据了。详情页的数据可以直接拿到⽐较简单。
然后在这⾥解释⼀下为什么要⽤while True死循环,因为携程在换页的时候它的url是不会变化的,所以这⾥只能⽤selenium的⾃动点击功能,让它在采完第⼀页数据之后⾃动跳转下⼀页进⾏采集,设置好你要爬取的页码,也就是我代码⾥的self.page的值,达到爬取的页数就跳出循环即可。
到了爬取详情页这⼀步,就看你想采什么样的数据去写规则了。在这⾥我只提⼀点,不难但是⿇烦,⼤家在往下看之前也可以先思考⼀下。看下图。
图中的内容,有景点介绍 开放时间 优待政策⼏栏,但不是每个景点都是这⼏个,有的是只有⼀个,有的还有⼀个服务设备栏,⽽且看它的前端代码,属性标签啥的都是⼀模⼀样的,遇到这种情况如果是你会怎么去获取,才能保证不会少拿⽽且⼜能正确对应上数据?
思考令⼈进步。。。
下⾯给出我的答案!
springmvc流程是什么
我这⾥是把这个栏⽬的标题以及内容分别使⽤xpath提取形成两个列表,因为不管到底有⼏个内容,它的标题跟内容都肯定是⼀⼀对应上的,⽽列表是有序的。列表出来之后就是使⽤dict(zip(desc_title_list, desc_list)),先转json再转字典,标题就是key值,内容就是value 值。如果要单独展⽰就遍历字典就可以了。这⼀步我代码⾥没写,⼤家⾃⼰去写吧。
要注意的点⼤致就这些,下⾯贴我的完整代码
import pandas
import re
import time
import requests
import urllib3
from lxml import etree
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
urllib3.disable_ptions.InsecureRequestWarning)
class Jy_jd(object):
def__init__(self):
options = Options()
options.add_argument('--headless')
self.chrome = Chrome(options=options)
(
'ip/things-to-do/list?pagetype=city&citytype=dt&keyword=%E6%8F%AD%E9%98%B3&pshowcode=Ticket2')
time.sleep(3)
self.page =1
self.headers ={
'cookie':'Session=SmartLinkCode=U155952&SmartLinkKeyWord=&SmartLinkQuary=&SmartLinkHost=&SmartLinkLanguage=zh; _RSG=KqK3qETf
'cookie':'Session=SmartLinkCode=U155952&SmartLinkKeyWord=&SmartLinkQuary=&SmartLinkHost=&SmartLinkLanguage=zh; _RSG=KqK3qETf a143fOqQl4rFXB; _RDG=282f24100640c82731283334fcc3364464; _RGUID=406
4a5d3-b40d-4d14-b84f-d44bdad18a43; Union=OUID=index&AllianceID= 4897&SID=155952&SourceID=&createtime=1600831032&Expires=1601435831593; MKT_OrderClick=ASID=4897155952&AID=4897&CSID=155952&OUI D=index&CT=1600831031597&CURL=https%3A%ip%2F%3Fsid%3D155952%26allianceid%3D4897%26ouid%3Dindex&VAL={"pc_vid" :"1600831028743.427gzc"}; MKT_CKID=1600831031634.5olt5.f6pj; MKT_CKID_LMT=1600831031635; _ga=GA1.2.248639397.1600831032; _gid=GA1.2 .1954297618.1600831032; MKT_Pagesource=PC; GUID=09031031210931119554; nfes_isSupportWebP=1; appFloatCnt=1; nfes_isSupportWebP=1; ASP .NET_SessionSvc=MTAuNjAuMzUuMTQ2fDkwOTB8amlucWlhb3xkZWZhdWx0fDE1ODkwMDMyMjQ5NDI; U_TICKET_SELECTED_DISTRICT_CITY=%7B %22value%22%3A%7B%22districtid%22%3A%22835%22%2C%22districtname%22%3A%22%E6%8F%AD%E9%98%B3%22%2C%22isOversea%22%3An ull%7D%2C%22createTime%22%3A1600847243848%2C%22updateDate%22%3A1600847243848%7D; _RF1=113.118.204.141; _gat=1; _pd=%7B%22r %22%3A1%2C%22d%22%3A614%2C%22_d%22%3A613%2C%22p%22%3A634%2C%22_p%22%3A20%2C%22o%22%3A655%2C%22_o%22%3A21%2 C%22s%22%3A668%2C%22_s%22%3A13%7D; _bfa=1.1600831028743.427gzc.1.1600843833503.1600847244099.5.49.10650038368; _bfs=1.30; _bfi= p1%3D290510%26p2%3D290510%26v1%3D49%26v2%3D48; _jzqco=%7C%7C%7C%7C16
00831031803%7C1.1555887407.1600831031625.16008495 09140.1600849530503.1600849509140.1600849530503.0.0.0.19.19; __zpspc=9.4.1600846262.1600849530.14%232%7Cwww.baidu%7C%7C%7C %25E6%2590%25BA%25E7%25A8%258B%7C%23',
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', }
def get_url(self):
while True:
content = self.chrome.find_element_by_class_name('right-content-list').get_attribute('innerHTML')
cons = re.findall(r'href="(.*?)" title="(.*?)"', content)
for con in cons:
self.detail_url ='https:'+ con[0]
self.title = con[1]
print(self.detail_url, self.title)
<_detail()
self.chrome.find_element_by_class_name('u_icon_enArrowforward').click()
time.sleep(1)
self.page +=1
if self.page ==120:
break
def get_detail(self):
detail_con = (self.detail_url, verify=False, headers=self.headers).text
这是什么颜的英文# time.sleep(2)
'''使⽤正则获取信息'''
self.rank =''.join(re.findall(r'rankText">(.*?)<', detail_con, re.DOTALL))
self.address =''.join(re.findall(r'景点地址</p><p class="baseInfoText">(.*?)<', detail_con, re.DOTALL))
print(self.rank, self.address, bile)
'''使⽤xpath获取信息'''
ret = etree.HTML(detail_con)
desc_cons = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleContent"]')
desc_titles = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleTitle"]')
desc_list =[]
python入门教程appdesc_title_list =[]
for d in desc_cons:
des =''.join(d.xpath('.//text()'))
desc_list.append(des)
for d in desc_titles:
des =''.join(d.xpath('.//text()'))
desc_title_list.append(des)
结构体定义写在哪desc_dict =dict(zip(desc_title_list, desc_list))
print(desc_dict)
'''获取图⽚链接'''
img_list =[]
imgs = re.findall(r'background-image:url\((.*?)\)', detail_con, re.DOTALL)
for img in imgs:
'''匹配到的同⼀张图⽚会有两种尺⼨,我们只要⼤图,所以把尺⼨为521*391的匹配出来即可'''
image = re.search(r'521_391', img)
if image:
img_list.append(img)固体废物采样随机数表法怎么用
print(img_list)
<_ticket()
def get_ticket(self):
id= self.detail_url.split('/')[-1]
id= self.detail_url.split('/')[-1]
print(id)
ticket_url = f'ip/ticket/dest/{id}?onlyContent=true&onlyShelf=true'
ticket_res = (ticket_url, verify=False, headers=self.headers).text
# time.sleep(1)
ticket_ret = etree.HTML(ticket_res)
ticket = ticket_ret.xpath('//table[@class="ticket-table"]//div[@class="ttd-fs-18"]/text()')
price = ticket_ret.xpath(
'//table[@class="ticket-table"]//td[@class="td-price"]//strong[@class="ttd-fs-24"]/text()')
print(ticket)
print(price)
'''拿到的列表⾥可能存在不确定数量的空值,所以这⾥⽤while True把空值全部删除,这样才可以确保门票种类与价格正确对应上''' while True:
try:
except:
break
while True:
try:
except:
break
'''
这⾥多⼀个if判断是因为我发现有些详情页即便拿到门票信息并剔除掉空值之后仍然存在⽆法对应的问题,原因是⽹页规则有变动,所以⼀旦出现这种情况需要使⽤新的匹配规则,否则会数据会出错(不会报错,但信息对应会错误)
'''
if len(ticket)!=len(price):英格兰联赛威尔士球队
ticket = ticket_ret.xpath(
'//table[@class="ticket-table"]/tbody[@class="tkt-bg-gray"]//a[@class="ticket-title "]/text()')
price = ticket_ret.xpath('//table[@class="ticket-table"]//strong[@class="ttd-fs-24"]/text()')
while True:
try:
except:
break
while True:
try:
except:
break
print(ticket)
print(price)
ticket_dict =dict(zip(ticket, price))
print(ticket_dict)
if __name__ =='__main__':
jy_jd = Jy_jd()
_url()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论