最近待业在家,每天除了睡觉和学python,还有个最头疼的事就是一日三餐吃什么,要好吃关键是不能重样,毕竟再好吃的菜吃多了都会腻。
菜做的多了,要买的材料自然少不了,但是应该买哪些,买多少,这又是个问题。买少了不够,买多了吃不完,去超市买一大堆材料回来,做菜的时候发现该买的没买到,这就尴尬了,总不能天天都往超市跑吧。
正好学了爬虫,就想着能不能去下厨房爬点数据下来,看看食材的哪些配料用的多,看着买总是没有错的。
当然了,也不能什么菜都爬下来,我要吃的都是些家常菜,所以下厨房里的【家常菜】、【快手菜】、【下饭菜】是最适合爬取的内容。【素菜】暂时没考虑,虽然穷,但还是想每餐都尽量能吃点肉……
同时,考虑到大家做的比较多的菜,所以标签上选择【最受欢迎】一栏。翻了一下,一共就10页,每一页20条数据,所以三个加起来数据量不超过600条(要去掉重复的,实际上去掉重复以后是438道菜谱)。
重点是下厨房的爬取很简单,没有复杂的异步加载方式的,而且要爬取的内容也很简单,标题(菜名),综合评分,多少人做过这道菜,以及最关键的【用料】。
前面的数据只是为了后期使用,方便做其他的数据分析,而用料是这次的关键。
爬取的过程很简单,直接看爬取数据的代码。
'''1.下饭菜,共10页/category/40078/pop/?page=102.家常菜,共10页/category/40076/pop/?page=103.快手菜,共10页/category/40077/pop/?page=10标题、评分、XX人做过 用料,原链接用料://div[@class="ings"]/table/tbody/tr/td[1]/text()'''import requestsfrom lxml import etreeimport pandas as pdURL = '/category/40076/pop/?page={}'headers = {'Host': '','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 QQBrowser/10.4.3587.400'}items = []def get_url(content):tree = etree.HTML(content)data_list = tree.xpath('//div[2][@class="normal-recipe-list"]/ul/li')for li in data_list:food_url = li.xpath('./div/a/@href')[0]food_url = '' + food_url# print(food_url)get_data(food_url)def get_data(food_url):response = requests.get(url = food_url,headers = headers)content = response.texttree = etree.HTML(content)title = tree.xpath('//h1[@class="page-title"]/text()')[0].strip()score = tree.xpath('//div[@class="stats clearfix"]/div[1]/span[1]/text()')[0]done = tree.xpath('//div[@class="stats clearfix"]/div[2]/span[1]/text()')[0]# print(done)material = tree.xpath('//div[@class="ings"]/table/tr/td[1]/a/text()')material = ' '.join(material)data = {'菜名':title,'评分': score,'做菜人数': done,'食材清单': material,'链接': response.url}items.append(data)def main():for i in range(10):print('正在爬取第%s页的数据' % (i + 1))url = URL.format(i+1)response = requests.get(url,headers = headers)content = response.textget_url(content)df = pd.DataFrame(items)df.to_excel('家常菜.xlsx')print('保存成功!')if __name__ == '__main__':main()
页面解析习惯用xpath,爬取到数据后保存到列表字典中,然后用pandas中的to_excel方法保存到excel文件中。(该方法每次爬取完毕后都会覆盖原来的文件)
我把下饭菜、家常菜和快手菜分别做3次爬取,保存在3个excel里面,所以在保存的时候需要改一下excel的名字。
其实可以把所有数据保存在一个excel里面的,但是我主要是图方便,不想写那么多代码。
爬取完毕!下面是做词云。
我没有把所以代码写到一起,爬虫和词云分开来做了…感兴趣的可以自己琢磨着放到一个py文件中。
词云的生成我用了下面这几个库:
import pandas as pdimport numpy as npimport jiebafrom PIL import Imagefrom wordcloud import WordCloudfrom matplotlib import pyplot as plt
说明:pandas库是导入excel文件,jieba库用来给文字分词,numpy和PIL库是把图片转成二维数组,wordcloud用于生成词云,而matplotlib则是输出和保存图片用。
首先,读取三个excel文件,然后用pandas的concat方法,把数据叠加到一起,然后删除空值以及去重,最后剩下438条数据。
data1 = pd.read_excel('下饭菜.xlsx')data2 = pd.read_excel('家常菜.xlsx')data3 = pd.read_excel('快手菜.xlsx')data = pd.concat([data1,data2,data3]).dropna() # 去除空值data = data.drop_duplicates(keep ='first') # 删除重复性print(len(data))
第二步是分词。
# 可以不是用结巴分词,直接join后用自然就有空格已经分好了词,但是相对不那么准确# 所以可以用结巴再次分词,词汇量就会多一些food = list(data['食材清单'])string = ' '.join(food)cut = jieba.cut(string)text = ' '.join(cut)
其实食材清单这个数据用空格连成一整个str以后,材料之间本身就有空格。下面图中第一条没有分词,第二条是用结巴分词后的数据,会有一些差别。
比如第一条的豆瓣酱会完整显示,但是分词后可能豆瓣和酱是两个词,这个看个人取舍了。
第三步,把图片转换成二维数组。
这里要提前去网上找一张白底的图片,方便把词云写进不是白底的部分,比如图片搜索【大树 白底】,然后找一些纯白底色,合适的就行。
# 把图片转换为数组img = Image.open('timg.jpg')img_arry = np.array(img)
第四步,通过wordcloud方法,生成词云图片。更多wordcloud方法可以去参考官方资料,我这里写的比较简单。
wc = WordCloud(background_color='white', # 设置背景font_path='msyh.ttc', # 设置字体mask = img_arry)wc.generate_from_text(text)
马上就大功告成了。
最后一步,把生成的词云图片,用matplotlib库显示出来,以及保存到文件夹中。
fig = plt.figure(1)plt.imshow(wc)plt.axis('off') # 不显示坐标轴plt.savefig('食材词云.png',dpi=300) # 保存图片,dpi是像素大小
到此所有部分就完成了,在文件夹中应该会生成一个食材词云的图片。
以及可以拿去发朋友圈装X了。(我这里用的是一张地球的白底图,所以是圆的)
完整的生成词云的代码:
import pandas as pdimport numpy as npimport jiebafrom PIL import Imagefrom wordcloud import WordCloudfrom matplotlib import pyplot as pltdata1 = pd.read_excel('下饭菜.xlsx')data2 = pd.read_excel('家常菜.xlsx')data3 = pd.read_excel('快手菜.xlsx')data = pd.concat([data1,data2,data3]).dropna() # 去除空值data = data.drop_duplicates(keep ='first') # 删除重复性print(len(data))# 可以不是用结巴分词,直接join后用自然就有空格已经分好了词,但是相对不那么准确# 所以可以用结巴再次分词,词汇量就会多一些food = list(data['食材清单'])string = ' '.join(food)cut = jieba.cut(string)text = ' '.join(cut)# print(string,'\n',text)# 把图片转换为数组img = Image.open('timg.jpg')img_arry = np.array(img)wc = WordCloud(background_color='white',font_path='msyh.ttc', # 设置字体mask = img_arry)wc.generate_from_text(text)fig = plt.figure(1)plt.imshow(wc)plt.axis('off')plt.savefig('食材词云.png',dpi=300)