此篇内容使用到了以下模块:
1.使用openpyxl实现excel的读写
2.使用pypinyin实现汉子转拼音
3.使用geohash获取经纬度编码
4.使用requests中的utils方法实现cookies转字典和字典转cookies
5.使用json对列表和字典以及字符串之间进行转换
通过此次的学习可以爬取到全国2000多个城市指定位置附近的商家信息,如果再进一步挖掘的就具备了很大的商业价值
import requests
from pypinyin import lazy_pinyin
import geohash
import json
import openpyxl
session = requests.session()
# 将处理后的信息写入excel文件中
def write_info():
rest_list = get_nearby_restaurants_by_menu()
if rest_list != False:
# 新建excel
wb = openpyxl.Workbook()
# 获取工作表
sheet = wb.active
# 工作表名称
sheet.title = "饿了么商家信息"
# 设置单元格的列宽
sheet.column_dimensions['A'].width = 40
sheet.column_dimensions['B'].width = 20
sheet.column_dimensions['C'].width = 60
sheet.column_dimensions['D'].width = 20
sheet.column_dimensions['E'].width = 30
# 表头信息
headers =['商家名称','月销量','商家活动','配送费','营业时间']
sheet.append(headers)
# 写入数据
for rest in rest_list:
sheet.append([rest['name'],rest['order_num'],rest['activities'],rest['ship_fee'],rest['open_hours']])
# 保存数据
wb.save("饿了么商家信息.xlsx")
# 信息处理,获取所需要的信息
def get_result(res):
restaurants_infos = []
for info in res:
infos = {}
name = info['name'] # 商家名称
recent_order_num_display = info['business_info']
order_num = json.loads(recent_order_num_display)['recent_order_num_display'] # 月销量
open_hours = info['opening_hours'][0] # 营业时间
latitude = info['latitude'] # 商家地理位置经纬度
longitude = info['longitude']
piecewise_agent_fee = info['piecewise_agent_fee']['tips'] # 配送费
activities = info['activities'][0]['tips'] # 活动
infos['name'] = name
infos['order_num'] = order_num
infos['open_hours'] = open_hours
infos['latitude'] = latitude
infos['longitude'] = longitude
infos['ship_fee'] = piecewise_agent_fee
infos['activities'] = activities
restaurants_infos.append(infos)
# print(name + " " + str(order_num) + " " + str(open_hours) + " " + str(latitude) + " " + str(
# longitude) + " " + str(piecewise_agent_fee) + " " + activities)
return restaurants_infos
# 爬去附近商家信息
def get_nearby_restaurants_by_menu():
# 是否登录成功
login_flag = login_with_cookies()
if login_flag == 200:
print("=====================登陆成功=====================")
else:
print("=====================登陆失败=====================")
return False
city = input("请输入所在城市:(eg:杭州市输入【杭州】)")
menu_info = print_menu(city)
print("您选择获取【{}】类别商家的信息".format(menu_info['name']))
restaurants_infos = []
for i in range(0,48,24):
every_info = []
print("***************************正在爬取第{}页***************************".format(i // 24 + 1))
rest_url = 'https://www.ele.me/restapi/shopping/restaurants'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36',
'referer':'https://www.ele.me/place/wtmkhzfkmgh1?latitude={}&longitude={}'.format(menu_info['nearby_latitude'],menu_info['nearby_longitude'])
}
ids = []
if menu_info['name'][:1] == "0":
ids = menu_info['ids']
else:
ids.append(menu_info['id'])
rest_data = {
'extras[]':'activities',
'geohash':menu_info['nearby_geohash'],
'latitude':str(menu_info['nearby_latitude']),
'longitude':str(menu_info['nearby_longitude']),
'limit':'24',
'offset':str(i),
'restaurant_category_ids[]':ids,
'terminal':'web'
}
res = session.get(rest_url,headers=headers,params=rest_data).json()
# 数据处理
every_info = get_result(res)
restaurants_infos.extend(every_info)
return restaurants_infos
# 获取所选择菜单的信息
def print_menu(city):
menu_list = get_menu_info(city)
print("*"*90)
for menu in menu_list:
if menu['name'][:2] in ('4 ','9 ','14'):
print(menu['name'])
else:
print(menu['name'],end='\t\t\t')
print("*" * 90)
num = int(input("请选择对应菜单的编号:(eg:0)"))
return menu_list[num]
# 获取附近商家的菜单分类选项
def get_menu_info(city):
nearby_geohash,nearby_latitude,nearby_longitude = get_currAddr_info(city)
menu_url = 'https://www.ele.me/restapi/shopping/v2/restaurant/category'
menu_data = {
'latitude':nearby_latitude,
'longitude':nearby_longitude
}
res = session.get(menu_url,params=menu_data).json()
i = 0
menu_list = []
for menu in res:
if i == 0:
menu_info = {'nearby_geohash':nearby_geohash,'nearby_latitude':nearby_latitude,'nearby_longitude':nearby_longitude,'name':'{} {}'.format(i,menu['name']),'ids':menu['ids']}
else:
menu_info = {'nearby_geohash':nearby_geohash,'nearby_latitude':nearby_latitude,'nearby_longitude':nearby_longitude,'name':'{} {}'.format(i,menu['name']),'id':menu['id'],'ids':menu['ids'],'sub_categories':menu['sub_categories']}
menu_list.append(menu_info)
i += 1
return menu_list
# 获取当前收货地址的经纬度信息
def get_currAddr_info(city):
# 获取经纬度以及geohash编码
latitude, longitude,geohash_code = get_geohash(city)
addr = input("请输入收货地址:")
nearby_url = 'https://www.ele.me/restapi/bgs/poi/search_poi_nearby'
nearby_data = {
'geohash': geohash_code,
'keyword': addr,
'latitude': latitude,
'limit': ' 20',
'longitude': longitude,
'type': ' nearby'
}
# 获取收货地址的经纬度信息
res = session.get(nearby_url,params=nearby_data).json()
return res[0]['geohash'],res[0]['latitude'],res[0]['longitude']
# 使用cookies登录
def login_with_cookies():
# 先从cookies中获取信息
cookies = get_cookies()
if cookies != False:
session.cookies = cookies
return 200
else:
return login_with_phone()
# 模拟使用手机号登录
def login_with_phone():
url = 'https://h5.ele.me/restapi/eus/login/mobile_send_code'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'
}
tel = input("请输入手机号:")
data = {
'captcha_hash': '',
'captcha_value': '',
'mobile': tel,
'scf': 'ms'
}
res = session.post(url, headers=headers, data=data).json()
validate_token = ''
try:
validate_token = res['validate_token']
except:
print("无法获取token\t{}".format(res))
return
# 输入验证码并登录
login_url = 'https://h5.ele.me/restapi/eus/login/login_by_mobile'
code = input("请输入验证码:")
login_data = {
'mobile': tel,
'scf': ' ms',
'validate_code': code,
'validate_token': validate_token
}
# 模仿登陆
res = session.post(login_url, headers=headers, data=login_data)
# 获得cookies,将其写入文件中
write_cookies(res.cookies)
return res.status_code
# 读取cookies信息
def get_cookies():
try:
file = open("login_cookie.txt", 'r', encoding='utf-8')
cookie_json = file.read()
# 将json转换为字典
cookie_dict = json.loads(cookie_json)
# 字典转换为cookie
cookies = requests.utils.cookiejar_from_dict(cookie_dict)
return cookies
except FileNotFoundError:
return False
# 写入cookies
def write_cookies(cookies):
# # 将cookies转换为字典
cookies_dict = requests.utils.dict_from_cookiejar(cookies)
# 将字典转换为字符串
cookies_json = json.dumps(cookies_dict)
file = open("login_cookie.txt", 'w', encoding='utf-8')
file.write(cookies_json)
file.close()
# 根据经纬度获取geohash编码
def get_geohash(city):
latitude,longitude = get_lati_and_longi(city)
code= geohash.encode(latitude,longitude,12)
return latitude,longitude,code
# 获取经纬度信息
def get_lati_and_longi(city):
# 获取首汉子的首字母,以及所有汉子的首字母
first_word,all_first_word= get_first_word(city)
cities_url = "https://www.ele.me/restapi/shopping/v1/cities"
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'
}
cities= requests.get(cities_url,headers=headers).json()
for key,value in cities.items():
# 根据首字母定位数据
if key == first_word:
# 根据所有的首字母定位数据
for city_info in value:
if city_info['abbr'] == all_first_word and city_info['name'] == city:
return city_info['latitude'],city_info['longitude']
return
# 根据输入的城市将其转换为对应的拼音
def get_first_word(city):
# 汉子转拼音
to_pinyin = lazy_pinyin(city)
# 遍历获取每一个汉子的首字母,并转换为大写
first_word_list = []
for letter in to_pinyin:
first_word_list.append(letter[:1].upper())
# 第一个汉子的首字母
first_leter_first_word = first_word_list[0]
# 所有拼音的首字母
all_letter_first_word = ''
for letter in first_word_list:
all_letter_first_word += letter
return first_leter_first_word,all_letter_first_word
# 调用方法
write_info()
测试:
第一种:首次登录需要手机号以及验证码登录
请输入手机号:***********
请输入验证码:******
=====================登陆成功=====================
请输入所在城市:(eg:杭州市输入【杭州】)杭州
请输入收货地址:古墩路243号
******************************************************************************************
0 全部商家 1 美食 2 快餐便当 3 特色菜系 4 全球美食
5 小吃夜宵 6 甜品饮品 7 商店超市 8 鲜花绿植 9 医药健康
10 早餐 11 午餐 12 下午茶 13 晚餐 14 夜宵
******************************************************************************************
请选择对应菜单的编号:(eg:0)1
您选择获取【1 美食】类别商家的信息
***************************正在爬取第1页***************************
***************************正在爬取第2页***************************
第二种:已经登陆过后,再次登录只需要读取cookies即可
=====================登陆成功=====================
请输入所在城市:(eg:杭州市输入【杭州】)郑州
请输入收货地址:二七广场
******************************************************************************************
0 全部商家 1 美食 2 快餐便当 3 特色菜系 4 全球美食
5 小吃夜宵 6 甜品饮品 7 商店超市 8 鲜花绿植 9 医药健康
10 早餐 11 午餐 12 下午茶 13 晚餐 14 夜宵
******************************************************************************************
请选择对应菜单的编号:(eg:0)10
您选择获取【10 早餐】类别商家的信息
***************************正在爬取第1页***************************
***************************正在爬取第2页***************************
爬取到的内容存入excel这里就不再提供截图
以上功能还有很多需要优化的地方,比如:对输入的手机号和验证码的判断,爬取数据的优化,cookiies是否过期等等
关于代码过程中遇到的问题:
1. geohash导入报错的问题
1.1 将python安装目录中 Lib\site-packages\文件夹中的Geohash文件夹名称改为geohash eg: Lib\site-packages\Geohash ->geohash
1.2 将修改后的geohash文件夹中的__init__.py中的 from geohash import decode_exactly, decode, encode改为from .geohash import decode_exactly, decode, encode
1.3 将修改后的Lib\site-packages\geohash文件夹复制到Lib目录下 Lib\geohash
2. 在测试过程中需要图片验证码导致无法模拟登陆
2.1 这个是因为手机号登录次数过于频繁,一般三次以内是不需要图片验证码的
这篇博客介绍了如何使用Python模拟登录饿了么网站,并爬取指定位置附近的商家信息。涉及的模块包括openpyxl进行Excel读写、pypinyin实现汉字转拼音、geohash获取经纬度编码、requests的cookies处理以及json数据转换。通过学习,可以爬取全国多地的商家数据,具有潜在的商业价值。内容中还提到了登录过程中的问题及解决办法,如geohash导入错误和图片验证码的应对策略。
729

被折叠的 条评论
为什么被折叠?



