签名验证涉及到客户端和服务器端,每个客户端在服务器上有一个对应的 app_id 和 app_key,大致步骤如下:
签名验证是防止恶意连接和数据被篡改的有效方式之一,也是目前后端API最常用的防护方式之一。与Cookie、User-Agent、Host和Referer等请求头域不同,用于签名验证的信息通畅被放在请求正文中发送到服务器端。
# 美团美食某一店铺的url
url = "https://www.meituan.com/meishi/150086049/"
任务: 爬取该网站页面中的评论信息;
进入该网站后,网站会从API接口读取数据,然后通过JavaScript操作DOM来更改页面显示的内容。
我们可以打开古尔刚的network,查看网络请求记录,观察数据从什么地方读取的。如下:
经过查验,获取评论数据的url是一条文档类型为xhr的请求,该请求对应的请求总览为:
Request URL: https://www.meituan.com/meishi/api/poi/getMerchantComment?uuid=dddd1986600440e09554.1592745353.1.0.0&platform=1&partner=126&originUrl=https%3A%2F%2Fwww.meituan.com%2Fmeishi%2F150086049%2F&riskLevel=1&optimusCode=10&id=150086049&userId=&offset=0&pageSize=10&sortType=1
Request Method: GET
Status Code: 200 OK
Remote Address: 101.236.12.4:443
Referrer Policy: no-referrer-when-downgrade
可以看到url地址包含了一些参数
切换到Response面板,此时请求对应的部分响应正文为:
{"status":0,"data":{"tags":[{"count":23,"tag":"味道赞"},{"count":22,"tag":"服务热情"},{"count":12,"tag":"上菜快"},{"count":12,"tag":"性价比高"},{"count":9,"tag":"牛肉赞"},{"count":8,"tag":"环境很安静"},{"count":6,"tag":"回头客"},{"count":6,"tag":"价格实惠"},{"count":1,"tag":"到店自提"},{"count":4,"tag":"分量少"}],"comments":[{"userName":"PoG230641790","userUrl":"","avgPrice":83,"comment":"我昨天去消费霸王餐代金券,看到其它家餐馆人都不多,可这家店很热闹,座无虚席。刚刚进来有人领位。想那么多人上菜可能慢,可是还挺快。他们都各司其职,忙中有序。这家火锅底料也是挺好的,比较经济实惠58元还是鸳鸯锅,牛腩汤还真是有牛腩。特别推荐他们家的嫩牛肉,真的非常棒,肉嫩,肉片大,肉整齐。特别推荐小料,其实都不是简单小料了还包括了小菜,小吃和水果。丰富,吃的很开心。\n【性价比】","merchantComment":"亲爱的顾客您好!非常感谢您对黄门望京店的支持与认可、我们也在努力做着全宇宙最好吃的火锅,期待您的下次光临、在此黄门全体员工祝您工作顺利、阖家幸福!","picUrls":[{"id":-51665313,"url":"http://p0.meituan.net/shaitu/3adf2f18d631a61cfb95e057b1b9510f496092.jpg"},{"id":-51884247,"url":"http://p1.meituan.net/shaitu/d7d959529e9b24a94dbe18380e7df9f6355489.jpg"},{"id":-51665312,"url":"http://p1.meituan.net/shaitu/e5ee3bc935d1a178c35e6eb135d30eb8445419.jpg"}],"commentTime":"1592189742062","replyCnt":1,"zanCnt":0,"readCnt":162,"hilignt":"","userLevel":0,"userId":"1953357495","uType":2,"star":50,"quality":true,"alreadyZzz":false,"reviewId":"2365531985","menu":null,"did":0,"dealEndtime":null,"anonymous":false},{"userName":"IHU188448956","userUrl":"","avgPrice":83,"comment":"乘坐地铁还是很方便的 环境舒适 服务热情 鸭血和酥肉每次都是必点菜品 鲜鸭血涮完很嫩 酥肉一直都很赞 手切羊肉和嫩牛肉都不错 小吃台还有凉菜泡菜 冰粉 西瓜 吃火锅配冰粉和西瓜吃完就知道有多舒服 还会再去的 祝老板生意兴隆","merchantComment":"亲爱的顾客您好!非常感谢您对黄门望京店的支持与认可、我们也在努力做着全宇宙最好吃的火锅,期待您的下次光临、在此黄门全体员工祝您工作顺利、阖家幸福!","picUrls":[{"id":-63296083,"url":"http://p0.meituan.net/shaitu/d281e848df65c67047c231f1e74e4f743592443.jpg"},{"id":-63296082,"url":"http://p0.meituan.net/shaitu/a1c00cf7a7b65acc0aa76b073bd1b8dc3283653.jpg"},
这正是我们想要的评论数据,我们只需要向这个URL地址发起请求就可以即可得到想要的内容。
使用postman模拟发起请求,看一下能否拿到数据。postman请求结果为:
没有拿到想要的结果,说明这个API接口很可能有反爬虫。我们可以对请求信息进行分析,
请求头如下:
GET /meishi/api/poi/getMerchantComment?uuid=dddd1986600440e09554.1592745353.1.0.0&platform=1&partner=126&originUrl=https%3A%2F%2Fwww.meituan.com%2Fmeishi%2F150086049%2F&riskLevel=1&optimusCode=10&id=150086049&userId=&offset=0&pageSize=10&sortType=1 HTTP/1.1
Host: www.meituan.com
Connection: keep-alive
Accept: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Referer: https://www.meituan.com/meishi/150086049/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _lxsdk_cuid=170f2895e89c8-0afceb2708f288-5373e62-144000-170f2895e89c8; __mta=188119703.1584617054220.1584941252974.1591601441171.3; ci=1; rvct=1; _hc.v=45417454-dc78-7171-c275-86368d2534d1.1591601543; client-id=6db9a6d5-4100-4e6e-9ab5-e3844f54770f; uuid=dddd1986600440e09554.1592745353.1.0.0; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _lxsdk=170f2895e89c8-0afceb2708f288-5373e62-144000-170f2895e89c8; lat=39.995966; lng=116.468722; _lxsdk_s=172d7055ff6-73a-4e4-c8d%7C%7C8
除了请求头之外,还多了一条QueryStringParameter,也称为查询参数,
uuid: dddd1986600440e09554.1592745353.1.0.0
platform: 1
partner: 126
originUrl: https://www.meituan.com/meishi/150086049/
riskLevel: 1
optimusCode: 10
id: 150086049
userId:
offset: 0
pageSize: 10
sortType: 1
可以看到,请求正文汇总的orginUrl和我们的url一致。
因为签名验证使用的是AJAX,因此,我们可以再JavaScript文件中搜索riskLevel、optimusCode、offset等关键字
最终,我们在index.js@53635fc文件中找到了对应的字符。
然后逆向JS。
再使用Python代码实现目标网站index.js@53635fc文件中的JavaScript代码逻辑,就能够请求到想要的数据了