Python学好了,飞机票你还买不到么?

项目:机票数据采集

使用模块:requests(请求模块),js2py(js执行模块),json(解析json),xpath(解析网页)。

小编推荐大家可以加我的扣扣群 735934841 。里面有海量视频教程和学习资料免费领取,不失为是一个学习的好地方,欢迎你的到来。一起交流学习!共同进步!!

项目流程:

分析网站数据来源。

编写爬虫脚本。

验证数据准确性。

js逆向破解参数生成。

更换请求参数城市(飞机起飞城市和落地城市或日期)测试结果是否正常。

1.分析网站数据来源

进入艺龙机票列表搜索页,附上链接 http://flight.elong.com/flightsearch/list?departCity=bjs&arriveCity=sha&departdate=2018-12-2 4,链接参数日期自行更改。

一般情况数据为调用接口获得,或是在页面中嵌入,这里很明显是调用了接口。

F12打开开发者工具(谷歌浏览器),选择network中的xhr,然后刷新页面或重新搜索,查看调用的接口。(这一步也可以使用抓包工具,推荐使用Fiddler,网上有许多汉化版的,看个人习惯吧。)

调用了四个接口,点击接口查看返回结果,确定数据来源。

看到出发机场,航空公司名称之类的英文,ok,就是这个了,点击进入Headers。

数据来源已经确定,下面我们来构造爬虫请求接口。

2.编写爬虫脚本

快速上手requests模块,链接已备好http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

直接上代码(提示:代码中的请求参数grabcode的值需要自己抓取,有时效性,过期无返回结果导致代码报错):

import requests #导入requests模块

#请求链接

url = 'http://flight.elong.com/search/ly/rest/list'

#构造请求头 接口中请求头有的参数最好全写上,之后再了解这些请求头信息是干什么的,这里不做介绍

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',

}

#请求参数

data = {

"p": '{"departCode":"bjs","arriveCityCode":"sha","departDate":"2018-12-24","searchType":"0","classTypes":null,"isBaby":0}',

"grabCode":'6793819',

}

#发起请求

html = requests.post(url, headers=headers,data=data).text

print(html)

有返回结果并且有数据证明我们请求成功了,但是我们还得进一步验证数据准确性。

3.验证数据是否准确

使用json进一步提取关键数据如航班号,最低价等。

import requests #导入requests模块

import json #导入json

#请求链接

url = 'http://flight.elong.com/search/ly/rest/list'

#构造请求头 接口中请求头有的参数最好全写上,之后再了解这些请求头信息是干什么的,这里不做介绍

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',

}

#请求参数

data = {

"p": '{"departCode":"bjs","arriveCityCode":"sha","departDate":"2018-12-24","searchType":"0","classTypes":null,"isBaby":0}',

"grabCode":'9151048',

}

#发起请求

html = requests.post(url, headers=headers,data=data).text

#json.loads转化json为一个字典 然后我们可以用字典方法取键和值

html = json.loads(html)["flightSelections"]

#创建结果列表

list = []

for i in html:#遍历所有航班

if len(i["Segments"]) == 1: #只提取单程,多程排除

flightnumber = i["Segments"][0]["FlightNumber"]

price = i["Segments"][0]["Price"]

#航班信息字典

item = {

"flight": flightnumber,

"price": price,

}

list.append(item)

print(list)

和网页价格对比:

结果正确,证明爬取成功。还没完,上面2,3过程提到grabCode参数的时效性,参数过期会导致接口无返回结果,json解析就会抛出异常。

4.js逆向分析加密请求参数grabCode的生成

接口请求参数中的加密参数都是有迹可循的,前端和后端必须使用相同的加密算法来保证参数的有效性。

后端代码我们不可能看得到,所以就要从前端来分析,前端通过js调用接口,调用接口的写法有很多种方式,如原生js,ajax,jquery等。

查找调用接口js位置:

通过关键字grabCode,来查找js调用接口的位置。(这里也可以通过其他方法如请求方式Post来搜索位置)

F12打开开发者工具,使用全局搜索search。

搜索参数名称grabCode

找到了,点击第一个搜索结果,进入查看js,点击左下角的图标格式化js。

使用ctrl+f搜索grabCode的位置

很清晰的可以看到这里就是使用了ajax调用list接口的方法url(接口地址),params(请求参数),methods(请求方式)。

grabCode的值是调用了abcdefg函数。(下面我们可以用js断点调试来获取函数abcdefg的位置,或是按照刚才的方法使用全局搜索来查找也可以,调试更方便一点)

js断点调试:

如图,在grabCode调用方法的行标点击,变成蓝色,表示断点成功,然后刷新页面。

搜索结果正在加载被截断,进一步证实了参数生成就是调用函数abcdefg。

这个小图标的功能叫”逐语句执行“或者叫”逐步执行“,这是我个人理解的一个叫法,意思就是,每点击它一次,js语句就会往后执行一句,它还有一个快捷键,F10。

我们点击一下,发现刚才断点的代码已被执行。鼠标箭头悬停在abcdefg函数上,点击方法可以直接跳过去。

上图对abcdefg函数做了一个解析,了解生成过程,总结一下就是调用网页源代码中的id为tsd的元素的属性值value,替换字符串中的某个值,并调用eval把字符串执行。

取消刚才的断点,在如图所示位置打上新断点,刷新页面。F10执行下一句。

和网页源代码对比一下,ok,正确。

不难看出上面的value值实际为js代码,eval函数会执行这些js代码。

模拟参数生成过程:

我们来使用python模拟一下他的过程:1.获取网页id==“tsd”的属性value的值。2.替换字符使用replace("/)^-1/gm", ")&-1")。3.执行js代码。

复制value的值,可以去网页,也可以在js中复制(这里复制出来的格式会有错误,导致js不能执行成功,我们直接去网页抓取好了)。

import requests,js2py

from lxml import etree

url_list ='http://flight.elong.com/flightsearch/list?departCity=BJS&arriveCity=SHA&departdate=2018-12-24&backdate=&searchType=0'

html_list = requests.get(url_list).text

html_list = etree.HTML(html_list)

js = html_list.xpath('//input[@id="tsd"]/@value')[0]

js = js.replace("/)^-1/gm", ")&-1")

code = js2py.eval_js(js)

print(code)

我们再把这个封装成一个函数来供第二步进行调用,搜索url中的三字码和日期可以用一样的(防止出错)。

更换搜索参数城市三字码或日期测试代码是否能正常运行并返回航班及其价格

下面附上全部代码,仅供参考学习。

import requests #导入requests模块

import json #导入json

import js2py #导入js执行模块

from lxml import etree #xpath使用lxml的etree解析

def ticket_api(a,b,c):

#请求链接

url = 'http://flight.elong.com/search/ly/rest/list'

#构造请求头 接口中请求头有的参数最好全写上,之后再了解这些请求头信息是干什么的,这里不做介绍

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',

}

#请求参数

data = {

"p": '{"departCode":"%s","arriveCityCode":"%s","departDate":"%s","searchType":"0","classTypes":null,"isBaby":0}'%(a,b,c),

"grabCode":grabCode(a,b,c),

}

#发起请求

html = requests.post(url, headers=headers,data=data).text

#json.loads转化json为一个字典 然后我们可以用字典方法取键和值

html = json.loads(html)["flightSelections"]

#创建结果列表

list = []

for i in html:#遍历所有航班

if len(i["Segments"]) == 1: #只提取单程,多程排除

flightnumber = i["Segments"][0]["FlightNumber"]

price = i["Segments"][0]["Price"]

#航班信息字典

item = {

"flight": flightnumber,

"price": price,

}

list.append(item)

print(list)

def grabCode(a,b,c):

url_list ='http://flight.elong.com/flightsearch/list?departCity=%s&arriveCity=%s&departdate=%s&backdate=&searchType=0'%(a,b,c)

html_list = requests.get(url_list).text

html_list = etree.HTML(html_list)

js = html_list.xpath('//input[@id="tsd"]/@value')[0]

js = js.replace("/)^-1/gm", ")&-1")

code = js2py.eval_js(js)

return code

if __name__ == '__main__':

a = "bjs"

b = "czx" #常州czx,上海sha

c = "2018-12-24"

ticket_api(a,b,c)

到这一步,基本上算是完成了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容