爬取薄荷网所有食物的营养数据,并分类放入excel中

最近想要减肥,想着先从食物入手,在网上查了一下,发现有一个叫薄荷的网站还是不错的,食物都做了详细的分类,并且所有的营养都做了数据的量化,作为制定饮食计划的参考还是不错的。打算先大致的看一下常见的食物营养做到心中有数,再来制定计划。我同时还发现了网上有一篇文章,已经有人爬过薄荷了,但是只是在列表也爬取了热量数据,并没有进到详情页去爬取其他的营养参数。

我们先进到薄荷食物页面,发现网站将所收录的食物分成了11个大类,我想是将每一个大类放进一个excel表格的sheet里,那么这样的话就有11个sheet了。

GKVHiV.png

再来看到每一个分类的链接,发现用了短链,在短链的前面应该加上网站的域名’www.boohee.com’,那么先把分类页面爬取下来即可。

GKZMJf.png

导包侠,先预测大概需要那些包

1
2
3
4
5
6
7
8
9
from multiprocessing import Process
from multiprocessing import Pool
import os
import requests
from bs4 import BeautifulSoup
from lxml import etree
import pandas as pd
import openpyxl
import time

1
2
3
4
5
6
7
8
9
10
11
def group_url():
url = 'http://www.boohee.com/food/'
res = requests.get(url)
html = res.text
bs = BeautifulSoup(html,"html.parser")
#装每种食物种类的url
li = bs.find(class_='row').find_all('li') #每种食物大类的url
for f in li: #f代表每种食物大类
group_url = f.find(class_="img-box").find('a')['href']
group_url = 'http://www.boohee.com'+group_url
yield group_url #group_url是每一种食物大类的url

因为设计是爬取了一个大类就写一次sheet,所以这里使用了yield,每爬取一次处理一次,剩下的后续等待。

进到分类里面之后就是该分类下面的食物列表了,我发现每一类下面食物大概都有10页的,一页有10种食物,那先把所有的翻页链接拿下。

GKZH0A.png

1
2
3
4
5
6
7
def book_url(group_url):
urls = [] #存储每类食物中下的翻页
for i in range(1,11):
page_url = group_url+'?page='+str(i)
urls.append(page_url)
# urls存储的是每一类食物中的所有页
return urls

在具体的一页中获取该页的所有食物链接,并进入每个链接中获取食物的所有信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def get_info(urls):
data = []
food_end = []
pool = Pool(processes=4)
info = []
info_url = [] #食物详情的url
s = pool.map(requests.get,urls)
for i in s:
html = i.text
bs = BeautifulSoup(html,"html.parser")
group = bs.find(class_='widget-food-list pull-right').find('h3').text #食物类别
end = bs.find_all(class_='img-box pull-left')
for j in end:
info_url.append('http://www.boohee.com{0}'.format(j.find('a')['href']))
data.append(pool.map(get_detil,info_url))
frame = pd.DataFrame(data=data[0] ,columns=['名称' ,'又名' ,'热量(大卡)' ,'碳水化合物(g)' ,'脂肪(g)' ,'蛋白质(g)' ,'建议'])
return group ,frame

上一段代码中的get_detil就是具体在详情页面中定位各种营养数据的实现过程

GKeAhV.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def get_detil(url):
# 获取详情页面的具体信息
print(url)
s = requests.get(url = url)
if s.status_code != 200:
N = ('', '', '', '', '', '', '')
return N
text = s.text
html = etree.HTML(text)
try:
name = html.xpath('/html/body/div[1]/div[3]/div/h2/a[2]')[0].tail #名字
except Exception as e:
name = ''
other_name = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[1]/div/ul/li[1]/b')[0].tail #别名
calories = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/div/dl[2]/dd[1]/span[2]/span')[0].text #热量
carbohydrate = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/div/dl[2]/dd[2]/span[2]')[0].text #碳水化合物
adipose = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/div/dl[3]/dd[1]/span[2]')[0].text #脂肪
protein = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/div/dl[3]/dd[2]/span[2]')[0].text #蛋白质
suggestion = html.xpath('/html/body/div[1]/div[3]/div/div[2]/div[1]/p/b')[0].tail #建议
return name ,other_name ,calories ,carbohydrate ,adipose ,protein ,suggestion

上面的get_detil的对名字做处理是后面运行的时候才加的,主要是发现了有一些食物在列表页面是有名字的,但是到了详情页面中的时候,名字字段就缺失了,这种情况下xpath的定位就会发生异常,所以我们这里就这样处理先。一开始想在列表也上用名字的,但是这样将会耗费大量的时间在请求上,所以用详情页中的面包屑导航中的信息,但有些面包屑会缺失掉一点。

GKmsaR.png

这是正常的面包屑

GKmHit.png

这是异常的面包屑,缺失了分类信息

爬取到的信息要保存,因为信息不是很多,而且我这台电脑上没有安装数据库,所以我就用excel进行保存了。不同的分类保存在不同的sheet里,一开始想直接用pandas模块的excel写入方法的,后面发现不行,找了挺多资料,也做了很多的尝试,发现用openpyxl模块可以实现。

1
2
3
4
5
6
7
8
def save_excel(data,sheet_name):
writer = pd.ExcelWriter('Excel_test.xlsx',engin='openpyxl')
book = openpyxl.load_workbook(writer.path)
writer.book = book
df = data
df.to_excel(excel_writer=writer,sheet_name=sheet_name)
writer.save()
writer.close()

后面就是把具体的实现步骤连接起来了。

1
2
3
4
5
6
7
8
9
if __name__ == '__main__':
start_time = time.time()
url = group_url()
for i in url:
r = book_url(group_url=i)
e = get_info(urls=r)
save_excel(data=e[1],sheet_name=e[0])
end_time = time.time()
print(end_time - start_time)

整个爬虫下来其实没有什么值得说的,如果是单线程的话耗时真的是太久,分析一下,这个爬虫其实最耗时应该是在获取详情的地方,写入excel的数据量并不是太大,所以针对请求做了多线程处理。一开始只是加了一处,发现处理起来快很多,后面在将爬取数据处理成dataFrame中也加入了多线程,整个爬虫的速度确实有变快。

这个爬虫不是太难,就简单的做一个练手的记录吧。

GKnSds.png

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------本文结束感谢您的阅读-------------