馬蜂窩之旅遊問答

上圖爲馬蜂窩的旅遊問答頁(http://www.mafengwo.cn/wenda/area-10206.html?sFrom=mdd),通過不斷點擊加載更多發送ajax請求更新頁面,通過抓包,可以得到獲取回答內容的接口,這是一個get請求,通過更換page來不斷的獲取新的內容。

不過最大請求page爲24,當page>24時,會返回空值。一共只能返回500不到的數據量。所以可以自己在搜索是添加標籤,如澳門美食。

這樣就可以增加獲取到的數據量噢。

import requests
url = "http://www.mafengwo.cn/qa/ajax_qa/more"
querystring = {"type":"0","mddid":"10206","tid":"","sort":"1","key":"","page":"1","time":""}
headers = {
'Pragma': "no-cache",
'Accept-Encoding': "gzip, deflate",
'Accept-Language': "zh-CN,zh;q=0.9",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Accept': "application/json, text/java, */*; q=0.01",
'Referer': "http://www.mafengwo.cn/wenda/area-10206.html?sFrom=mdd",
'X-Requested-With': "",
'cache-control': "no-cache",
'Postman-Token': "b0c95558-c509-4752-b49a-d80086e0a15a"
}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)

馬蜂窩之遊記

以成都遊記舉個栗子(http://www.mafengwo.cn/travel-scenic-spot/mafengwo/10035.html)。馬蜂窩的遊記有兩個接口,一個是最熱遊記,一個是最新遊記。最熱遊記只給提供300頁共3000條;最新遊記則是有多少給你看多少。所以只需爬取最新遊記就可以全部抓取。

這是一個post請求,一共有十個參數,_sn參數可以不用更換,就可以不斷改變page獲得內容。

也就是說,將page賦值2534的同時不改變_sn的值也可以獲取到遊記內容。

import requests
url = "http://www.mafengwo.cn/gonglve/ajax.php"
querystring = {"act":"get_travellist"}
payload = "mddid=10035&pageid=mdd_index&sort=2&cost=0&days=0&month=0&tagid=0&page=2534&_ts=1553332896149&_sn=a4ad17d822"
headers = {
'Pragma': "no-cache",
'Origin': "http://www.mafengwo.cn",
'Accept-Encoding': "gzip, deflate",
'Accept-Language': "zh-CN,zh;q=0.9",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Accept': "application/json, text/java, */*; q=0.01",
'Cache-Control': "no-cache",
'X-Requested-With': "",
'Referer': "http://www.mafengwo.cn/travel-scenic-spot/mafengwo/10035.html",
'cache-control': "no-cache",
'Postman-Token': "74506c28-c314-4238-b55d-b781360f6a2d"
}
response = requests.request("POST", url, data=payload, headers=headers, params=querystring)
print(response.text)

馬蜂窩之美食

關於美食篇,可顯示的頁面數也做了限制,只能顯示20頁共300條數據(http://www.mafengwo.cn/cy/10035/)

不過可以通過拼湊url分區獲取,以獲得大量數據,其中特色和分類這兩類不能同時選擇,因爲它們的id位於同一位置(0-0-id-0-0-1);而商圈類的id位於第二位(0-id-0-0-0-1);所以可以通過在第二位和第三位平湊不同的id號來獲取數據,比如(0-46549-7654-0-0-1)來定位春熙路的川菜。

在不斷點擊下一頁,可以得知這是一個get請求,僅改變第六位(0-id-id-0-0-page)來翻頁,如春熙路川菜第十五頁:http://www.mafengwo.cn/cy/10035/0-46549-7654-0-0-15.html

當然如果想要得到某家店的詳細信息,一定需要進入其詳情頁。(ul.poi-list > li:nth-child(1) > div.title > h3 > a)

import requests
url = "http://www.mafengwo.cn/cy/10035/"
headers = {
'Connection': "keep-alive",
'Upgrade-Insecure-Requests': "1",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
'Referer': "http://www.mafengwo.cn/cy/10035/0-0-9472-0-0-1.html",
'Accept-Encoding': "gzip, deflate",
'Accept-Language': "zh-CN,zh;q=0.9",
'cache-control': "no-cache",
'Postman-Token': "3670100a-7683-4e61-aeb1-b71bd4f1d6bd"
}
response = requests.request("GET", url, headers=headers)
print(response.text)

在這個頁面可以得到各個標籤的id~~~

馬蜂窩之蜂蜂點評

通過抓取美食訪問各個商戶的詳情頁,發現評論數據都放在了蜂蜂點評中(http://www.mafengwo.cn/poi/87950.html)

要抓取它的點評數據還是挺困難的,而且它只顯示五頁

點擊下一頁,一共五次得到下面的請求,所有的評論數據都在這一類url中。在這裏就和遊記有一些不同,這裏的_sn必須和params以及_ts保持一致。如果不一致就會返回空值。所以要獲得評論數據就必須找出_sn是如何生成的。

找到這個js文件http://js.mafengwo.net/js/hotel/sign/index.js?1552035728。在第363行和第364行打上斷點,然後點擊下一頁。

第363行會生成一個json變量 _0xe7fex39。在第364行,首先運行這一部分:(JSON[__Ox2133f[60]](_0xe7fex39) + _0xe7fex34)即生成一個字符串類型的變量:"{"_ts":"1553500557401","params":"{\"poi_id\":\"87950\",

\"page\":1,\"just_comment\":1}"}c9d6618dbc657b41a66eb0af952906f1"

然後再通過函數_0xe7fex2生成32位的字符串;最通過slice(2,12)函數對其進行切割,獲得2-12的字符串,這個就是_sn的值。

查找這個函數發現_0xe7fec函數將變量生成一個長度爲4的數組;在通過_0xe7fex10函數將數組生成對應的字符串;最後將_0xe7fex15拼接起來。

而拼接後的這串字符的2-12位就是_sn值。這整個加密過程就是常說的md5加密。右邊的加密結果和_0xe7fex15拼接起來的字符串是完全一樣的;

此時生成的_sn值bc28b3ed57就是對參數進行md5加密取2-12位的結果。

得到_sn值後,評論數據就可以很容易就得到。這裏要注意的是,在請求是必須把url拼接完整,否則只會返回一點點數據。另外在生成_sn時,參數qdata必須保持一致,是雙引號就是雙引號,有反斜槓就要有反斜槓,不然得不到正確的_sn值。

import hashlib
import requests
def par(t):
hl = hashlib.md5()
hl.update(t)
return hl.hexdigest()[2:12]
page=1
t=1553500557401
qdata='{"_ts":"'+str(t)+'","params":"{\\"poi_id\\":\\"87950\\",\\"page\\":'+str(page)+',\\"just_comment\\":1}"}c9d6618dbc657b41a66eb0af952906f1'
sn=par(qdata.encode('utf-8'))
print(sn)
url = "http://pagelet.mafengwo.cn/poi/pagelet/poiCommentListApi?"
querystring = {"callback":"jQuery181011036861119045205_1553502048335",
"params":"%7B%22poi_id%22%3A%2287950%22%2C%22page%22%3A{}%2C%22just_comment%22%3A1%7D".format(str(page)),
"_ts":t,
"_sn":sn,
"_":t+1}
headers = {
'Referer': "http://www.mafengwo.cn/poi/87950.html",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
}
for key,value in querystring.items():
url=url+key+'='+str(value)+'&'
url=url[:-1]
response = requests.request("GET", url, headers=headers)
print(response.text)

既然可以構建參數訪問前五頁的數據,那是否可以通過這種方式訪問第六頁呢?將page改爲6是可以成功獲取到數據的,抽取page=6的第一條評論的部分和第五面第一條對比一下。果真是想太多。。。。。。

馬蜂窩之景點

關於馬蜂窩的景點數據,也是需要各個參數和_sn保持一致的。這裏以四川的景點爲例說明。

先抓包,在xhr中點擊一次下一頁,就有生成三個頁面。其中所需要的內容在router.php中。

跟之前一樣,在第363行和第364行打上斷點,對變量進行md5加密。

可以看到下列結果和上圖的_sn值是完全一樣!

import hashlib
import requests
def par(t):
hl = hashlib.md5()
hl.update(t)
return hl.hexdigest()[2:12]
page=3
t=1553503246638
qdata = '{"_ts":"' + str(t) + '","iMddid":"12703","iPage":"' + str(page) + '","iTagId":"0","sAct":"KMdd_StructWebAjax|GetPoisByTag"}c9d6618dbc657b41a66eb0af952906f1'
sn=par(qdata.encode('utf-8'))
print(sn)
#e08b27d91f
url = "http://www.mafengwo.cn/ajax/router.php"
data = {
'sAct': 'KMdd_StructWebAjax|GetPoisByTag',
'iMddid': '12703',
'_ts': t,
'iPage': page,
'iTagId': '0',
'_sn': sn
}
headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
}
response = requests.request("POST", url, headers=headers,data=data)
print(response.text)

再比如這個頁面,當你點擊時就會生成,其_sn也通過md5生成。雖然這個頁面沒有返回什麼需要的內容,但可以鞏固一下加密方法。

馬蜂窩之當地玩樂

關於馬蜂窩的當地玩樂部分(http://www.mafengwo.cn/localdeals/0-0-M12703-0-0-0-0-0.html),沒有頁數的限制,可以不斷的請求下一頁。

每點擊一次下一頁,在xhr中就會新生成兩個頁面,其中返回數據的url是一個非常簡單的get請求,只需要改變page的值即可。

請求第37頁,可以看到返回的結果和頁面是完全一樣的

import requests
url = "http://www.mafengwo.cn/localdeals/ajax_2017.php"
querystring = {"act":"GetContentList","tag_group[9521][]":"all","tag_group[9365][]":"all","reduce[]":"all","booking_days[]":"all","from":"NaN","kw":"","to":"M12703","salesType":"NaN","page":"37","group":"NaN","sort":"smart","sort_type":"desc","limit":"20","booking_days%5B%5D":"all","reduce%5B%5D":"all","tag_group%5B9365%5D%5B%5D":"all","tag_group%5B9521%5D%5B%5D":"all"}
headers = {
'Accept-Language': "zh-CN,zh;q=0.9",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Accept': "application/json, text/java, */*; q=0.01",
'cache-control': "no-cache",
'Postman-Token': "c5ece4e3-cf93-4522-a9a6-0b06397ec81d"
}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)

馬蜂窩之驗證碼

打開酒店預訂頁面時,會有一個驗證碼跳出,再進入酒店頁面前必須要先通過這個驗證碼。

驗證碼在index這個頁面,通過get請求將驗證碼圖片保存到本地,同時需要保存這個網頁的cookie。因爲在發送驗證碼的時候需要這個cookie來提供依據,可以理解爲一張圖片對應一個cookie;通過cookie來驗證是否是這張圖片。

現在輸入正確的驗證碼,找到如下所示的這個url。這個url通過ccode,_ts,_sn三個參數拼接而成;ccode就是你要輸入的驗證碼,_ts就是時間戳。現在只需要把_sn構建出來就可以了。

還是在第363和364打上斷點,此時的_0xe7fex39爲{ccode:"fisy",_ts:1553507570004};然後對加上_0xe7fex34的字符串進行md5加密即可。

對比驗證碼驗證參數,可以看到是完全一樣的。

import hashlib
import requests
import time
def par(t):
hl = hashlib.md5()
hl.update(t)
return hl.hexdigest()[2:12]
headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
}
purl='http://www.mafengwo.cn/hotel/captcha/index'
html=requests.get(purl,headers=headers)
with open('img.jpg', 'wb') as f:
image = html.content
f.write(image)
f.close()
code = input("請輸入驗證碼")
o=html.cookies
PHPSESSID=o['PHPSESSID']
mfw_uuid=o['mfw_uuid']
oad_n=o['oad_n']
t=int(time.time()*1000)
data='{"_ts":"'+str(t)+'","ccode":"'+code+'"}c9d6618dbc657b41a66eb0af952906f1'
sn=par(data.encode('utf-8'))
print(sn)
data={
'ccode': code,
'_ts': str(t),
'_sn': sn
}
cookie="PHPSESSID={0}; mfw_uuid={1}; oad_n={2}; uva=s%3A78%3A%22a%3A3%3A%7Bs%3A2%3A%22lt%22%3Bi%3A1552989105%3Bs%3A10%3A%22last_refer%22%3Bs%3A6%3A%22direct%22%3Bs%3A5%3A%22rhost%22%3Bs%3A0%3A%22%22%3B%7D%22%3B; __mfwurd=a%3A3%3A%7Bs%3A6%3A%22f_time%22%3Bi%3A1552989105%3Bs%3A9%3A%22f_rdomain%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22f_host%22%3Bs%3A3%3A%22www%22%3B%7D; __mfwuuid=5c90bbb0-8d5f-5df8-50bb-acf3b2f39a12; UM_distinctid=1699904eca797-0b6edef1fe2585-36637902-13c680-1699904eca868e; ad_widget_footer_20190314formal_2_other=1%2C1vuh0fz; __mfwothchid=referrer%7Cwww.mafengwo.cn; __mfwlv=1553501567; __mfwvn=6; CNZZDATA30065558=cnzz_eid%3D20394471-1553047971-%26ntime%3D1553506977; __mfwlt=1553508203".format(PHPSESSID,mfw_uuid,oad_n)
url='http://www.mafengwo.cn/hotel/captcha/check?ccode={0}&_ts={1}&_sn={2}'.format(code,str(t),sn)
headers = {
'Cookie': cookie,
'Accept-Encoding': "gzip, deflate",
'Accept-Language': "zh-CN,zh;q=0.9",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Accept': "application/json, text/java, */*; q=0.01",
'Referer': "http://www.mafengwo.cn/hotel/10035/",
'X-Requested-With': "",
'Connection': "keep-alive",
'cache-control': "no-cache",
'Postman-Token': "620f7d41-d1de-4fe1-a69c-5a770227337a"
}
x=requests.get(url,headers=headers)
print(x.text)

返回結果如下:

馬蜂窩之酒店

再輸入驗證碼後,就可以請求到包含酒店信息的網址了,這一部分同樣也是將參數和_sn配對,如果配對成功就可以返回相應的信息。

還是打開之前的js文件,通過斷點調試,得到進行md5加密的字符串。

通過修改裏面的參數就可以獲得任意網頁的酒店信息了。

import hashlib
import requests
import time
def par(t):
hl = hashlib.md5()
hl.update(t)
return hl.hexdigest()[2:12]
page=1
t=int(time.time()*1000)
fromdata='2019-03-28'
todata='2019-03-29'
url = "http://www.mafengwo.cn/hotel/ajax.php"
data='{"_ts":"'+str(t)+'","has_booking_rooms":"1","has_faved":"0","iAdultsNum":"2","iAreaId":"-1","iChildrenNum":"0","iDistance":"10000","iMddId":"10035","iPage":"'+str(page)+'","iPoiId":"","iPriceMax":"","iPriceMin":"","iRegionId":"-1","nLat":"0","nLng":"0","position_name":"","sAction":"getPoiList5","sCheckIn":"'+fromdata+'","sCheckOut":"'+todata+'","sChildrenAge":"","sKeyWord":"","sSortFlag":"DESC","sSortType":"comment","sTags":""}c9d6618dbc657b41a66eb0af952906f1'
sn=par(data.encode('utf-8'))
querystring = {"iMddId":"10035",
"iAreaId":"-1",
"iRegionId":"-1","iPoiId":"","position_name":"","nLat":"0","nLng":"0","iDistance":"10000",
"sCheckIn":fromdata,
"sCheckOut":todata,
"iAdultsNum":"2",
"iChildrenNum":"0",
"sChildrenAge":"",
"iPriceMin":"",
"iPriceMax":"",
"sTags":"","sSortType":"comment","sSortFlag":"DESC","has_booking_rooms":"1",
"has_faved":"0","sKeyWord":"","iPage":str(page),
"sAction":"getPoiList5","_ts":str(t),
"_sn":sn}
headers = {
# 'Cookie': "PHPSESSID=0ltaobjcharadcioh30akag7i7; mfw_uuid=5c90bbb0-8d5f-5df8-50bb-acf3b2f39a12; uva=s%3A78%3A%22a%3A3%3A%7Bs%3A2%3A%22lt%22%3Bi%3A1552989105%3Bs%3A10%3A%22last_refer%22%3Bs%3A6%3A%22direct%22%3Bs%3A5%3A%22rhost%22%3Bs%3A0%3A%22%22%3B%7D%22%3B; __mfwurd=a%3A3%3A%7Bs%3A6%3A%22f_time%22%3Bi%3A1552989105%3Bs%3A9%3A%22f_rdomain%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22f_host%22%3Bs%3A3%3A%22www%22%3B%7D; __mfwuuid=5c90bbb0-8d5f-5df8-50bb-acf3b2f39a12; UM_distinctid=1699904eca797-0b6edef1fe2585-36637902-13c680-1699904eca868e; ad_widget_footer_20190314formal_2_other=1%2C1vuh0fz; oad_n=a%3A3%3A%7Bs%3A3%3A%22oid%22%3Bi%3A1029%3Bs%3A2%3A%22dm%22%3Bs%3A15%3A%22www.mafengwo.cn%22%3Bs%3A2%3A%22ft%22%3Bs%3A19%3A%222019-03-28+10%3A28%3A46%22%3B%7D; __mfwlv=1553740127; __mfwvn=7; CNZZDATA30065558=cnzz_eid%3D20394471-1553047971-%26ntime%3D1553739181; __mfwlt=1553744294",
'Accept-Encoding': "gzip, deflate",
'Accept-Language': "zh-CN,zh;q=0.9",
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
'Accept': "application/json, text/java, */*; q=0.01",
'Referer': "http://www.mafengwo.cn/hotel/10035/",
'X-Requested-With': "",
'Connection': "keep-alive",
'cache-control': "no-cache",
'Postman-Token': "3b29182a-18b2-46a9-8a2a-d3cde4de70f9"
}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)

這樣就可以獲取數據啦。

關於馬蜂窩就做到這裏啦。有遺漏的地方歡迎補充。如果喜歡這篇文章的話可以點好看給個鼓勵噢。

本文來源zuobangbang
本文版權歸原作者所有,內容爲作者個人觀點,轉載目的在於傳遞更多信息,如涉及作品內容、版權等問題,可聯繫本站刪除,謝謝。

更多交流諮詢:18080942131 (同微信 加好友備註:搜狐)。

相關文章