犹记得本科的某段时期,点评上的霸王餐是让我走出校门,游荡京城的很大一个原因。而在其他时候,囊中羞涩的我只能感叹一句京城居不宜而更多地选择宅在宿舍。之后一方面是生活费变得充足,一方面是因为霸王餐的申请有些麻烦就逐渐忘记了继续在点评上继续报名。
真正产生写一个报名脚本的想法诞生在找工作时期,不过那时候一方面爬虫知识忘记了许多,另一方面也因为实在没有这个精力和心情来写,然后就拖到了现在......
话不多说,上来就是一段源码:
def find_activity():
headers = {
"Host": "m.dianping.com",
"Referer": "https://m.dianping.com/freemeal/index",
"User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Mobile Safari/537.36"
}
url = "https://m.dianping.com/astro-plat/freemeal/loadLotteryList?cityid=2&latitude=&longitude=&env=dp®ionParentId=0®ionId=0&category=0&sort=0&type=1&page={}"
index = 1
id_list = []
while True:
cur_url = url.format(str(index))
index += 1
res = requests.get(cur_url, headers=headers)
data = json.loads(res.text)["data"]
if data["pageEnd"]:
break
else:
print(data)
lotteryActivityList = data["lotteryActivityList"]
for item in lotteryActivityList:
id = item['offlineActivityId']
title = item['title']
type = item['type']
if type == 1:
id_list.append((id,title))
time.sleep(random.uniform(0.5, 1))
return id_list
if __name__ == '__main__':
find_activity()
此函数用来寻找所有可用的霸王餐活动,最后返回一个列表,包含活动名称和对应的编号。url中包含page,所以写了一个while循环找到所有页面的内容,直到pageEnd标识为True,然后结束循环,其他好像也没什么好说的。
有了编号就可以直接通过post提交表单来自动报名:
import requests
import time
import random
def sign_up(id_list):
sign_url = "http://s.dianping.com/ajax/json/activity/offline/saveApplyInfo"
for index in range(len(id_list)):
id = id_list[index][0]
title = id_list[index][1]
sign_headers = {
"Host": "s.dianping.com",
"Origin": "http://s.dianping.com",
"Referer": "http://s.dianping.com/event/{}".format(id),
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"
}
cookies = {
'fspop': '#',
'cy': '#',
'cye': '#',
'_lxsdk_cuid': '#',
'_lxsdk': '#',
'_hc.v': '#',
'dplet': '#',
'dper': '#',
'll': '#',
'ua': '#',
'ctu': '#',
'Hm_lvt_602b80cf8079ae6591966cc70a3940e7': '#',
's_ViewType': '#',
'_lx_utm': '#',
'Hm_lpvt_602b80cf8079ae6591966cc70a3940e7': '#',
'_lxsdk_s': '#'
}
data = {
'offlineActivityId': id,
'phoneNo': '#',
'shippingAddress': '',
'extraCount': '',
'birthdayStr': '',
'email': '',
'marryDayStr': '',
'babyBirths': '',
'pregnant': '',
'marryStatus': '0',
'comboId': '',
'branchId': '',
'usePassCard': '0',
'passCardNo': '',
'isShareSina': 'false',
'isShareQQ': 'false'
}
res = requests.post(sign_url, headers=sign_headers, cookies=cookies, data=data)
print(title, res.text)
time.sleep(random.uniform(0.5, 1))
cookies需要填自己账号正常访问产生的cookies,跑完一遍就将霸王餐报名成功啦。
除了一种情况:该活动有多家门店参加活动,但不通用,需要选择一家门店来报名。这个时候表单中branchId会有该门店的shopid值,为一串数字,不适用该数字形式的branchId会报名失败(仅针对多门店不通用情况):
branchId
但在页面中找不到这串数字,只能找到shopid的字符串:
shopid
而shop/k3VuR1XItjK7I1wW
和shop/1856704708
这俩url指向的是同一个地址,因此我认为点评隐藏了真正的shopid而将其编码后的结果作为shopid放了出来,后台可以将其对应起来而用户无法找到真实的shopid也就无法在提交表单时输入正确的branchId。
不过结果我一下午的尝试,真实branchId还是存在的,而且好像在店铺主界面shop/k3VuR1XItjK7I1wW就存在,奇怪,之前没有的,现在能够找到了:
请求店铺界面的返回
但是我也懒得写了,就这样吧,再爬号都要封了。
不说了,要被封号了
之前爬的时候没过滤type,导致报名了一堆丽人项目,这这这这这。。。我看60个名额的项目只有29个报名,谁知道有多坑,而且之后报上了还得手动退。赶紧再改改,加上对type的过滤后就只剩美食项目了。
效果
好啦,我们下期再见!