猫哥教你写爬虫 046--协程-实践-吃什么不会胖

吃什么不会胖?

低热量食物
食物的数量有千千万,如果我们要爬取食物热量的话,这个数据量必然很大。
使用多协程来爬取大量的数据是非常合理且明智的选择

如果我们要爬取的话,那就得选定一个有存储食物热量信息的网站才能爬到数据
薄荷网。它是一个跟健身减肥有关,且可以查询食物数据的网站

www.boohee.com/food/
任务: 用多协程爬取薄荷网的食物热量信息
简单浏览一下这个网站,你会发现一共有11个常见食物分类

点击【谷薯芋、杂豆、主食】这个分类,你会看到在食物分类的右边,有10页食物的记录,包含了这个分类里食物的名字,及其热量信息。点击食物的名字还会跳转到食物的详情页面。

我们可以从爬虫四步(获取数据→解析数据→提取数据→存储数据)入手,开始逐一分析

我们需要创建数据库
mysql> create database boohee character set utf8;
Query OK, 1 row affected (0.00 sec)
mysql> use boohee;
Database changed
mysql> create table food(id int primary key auto_increment, category varchar(20) not null, name varchar(200) not null, calorie varchar(200) not null);
Query OK, 0 rows affected (0.03 sec)
mysql> desc food;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment |
| category | varchar(20)  | NO   |     | NULL    |                |
| name     | varchar(200) | NO   |     | NULL    |                |
| calorie  | varchar(200) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)
复制代码

www.boohee.com/food/group/…
1代表第一个分类, page=1代表第一页

我们先来一个正常的版本, 按顺序执行的那种...
每个分类, 爬取三页, 看统计一下时间...
import requests
from bs4 import BeautifulSoup
import pymysql
import time
connection = pymysql.connect(user='root', password='root', db='boohee')
cursor = connection.cursor()
category_list = []
def create_table():
    cursor.execute('drop database boohee')
    cursor.execute('create database boohee character set utf8')
    cursor.execute('use boohee')
    cursor.execute(
        'create table food(id int primary key auto_increment, category varchar(20) not null, name varchar(200) not null, calorie varchar(200) not null)')
    connection.commit()
def get_category():
    soup = BeautifulSoup(requests.get(
        'http://www.boohee.com/food/').text, 'html.parser')
    li_tag_list = soup.find_all(
        'li', class_='col-md-4 col-sm-4 col-xs-12 item')
    for li_tag in li_tag_list:
        category_list.append(li_tag.find(
            'div', class_='text-box').find('a').text)
def get_food():
    for index, cate in enumerate(category_list):
        if index != 11:
            for i in range(1, 3):
                url = "http://www.boohee.com/food/group/{}?page={}".format(
                    index+1, i)
                soup = BeautifulSoup(requests.get(url).text, 'html.parser')
                for div_tag in soup.find_all('div', class_="text-box pull-left"):
                    category = cate
                    name = div_tag.find('a')['title']
                    calorie = div_tag.find('p').text[3:]
                    add_food(category, name, calorie)
        else:
            for i in range(1, 3):
                url = 'http://www.boohee.com/food/view_menu?page={}'.format(i)
                soup = BeautifulSoup(requests.get(url).text, 'html.parser')
                for div_tag in soup.find_all('div', class_="text-box pull-left"):
                    category = cate
                    name = div_tag.find('a')['title']
                    calorie = div_tag.find('p').text[3:]
                    add_food(category, name, calorie)
def add_food(category, name, calorie):
    sql = "insert into food(category,name,calorie) values({},{},{})".format(
        repr(category), repr(name), repr(calorie))
    print(sql)
    cursor.execute(sql)
    connection.commit()
if __name__ == "__main__":
    start = time.time()
    create_table()
    get_category()
    get_food()
    print(time.time() - start)
复制代码
看看运行效果...
C:\Users\Administrator\Desktop\demo>python -u "c:\Users\Administrator\Desktop\demo\just_test.py"
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','Easy Fun 紫薯营养粥','317 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','白粥(粳米),又叫稀饭,大米粥,白米粥,米粥,大米汤','46 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','白粥(籼米),又叫稀饭,大米粥,白米粥','59 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','玉米(鲜),又叫苞谷、珍珠米、棒子、玉蜀黍、苞米、六谷','112 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','燕麦片,又叫燕麦','338 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','面条(生),又叫面','301 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','面条(煮),又叫面','110 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','籼米粉,又叫米线、米粉、粉','356 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','面包','313 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','红薯,又叫地瓜、番薯、甘薯','90 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','小米粥','46 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','马铃薯,又叫土豆、洋芋、地蛋、山药蛋、洋番薯','81 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','包子(猪肉馅)','227 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','米饭,又叫大米饭,饭,蒸米','116 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','白薯,又叫山芋、红皮山芋,地瓜、甘薯','106 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','大米,又叫稻米、米、生米','346 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','全麦面包,又叫全麦面包、全麦吐司、全麦面包片','246 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','烙饼','259 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','花卷','214 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','油条','388 大卡(每100克)')
insert into food(category,name,calorie) values('谷薯芋、杂豆、主食','嘉顿 生命面包 450g','284 大卡(每100克)')
......
insert into food(category,name,calorie) values('菜肴','扒鲜芦笋','86 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','果汁猪扒','173 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','虾仁扒油菜','61 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','蒜蓉玉叩鸡胗','129 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','蔬菜扒素肠','90 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','凤尾菇扒蛋','100 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','扒蝴蝶虾','168 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','铁扒巴德好司牛排','144 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','德州五香脱骨扒鸡','168 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','扒素肠','116 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','白菜扒猪肝','54 大卡(每100克)')
insert into food(category,name,calorie) values('菜肴','蚝油芥蓝素肉丝','128 大卡(每100克)')
7.019520282745361
复制代码
差不多用来7秒...
我们看一下数据库...

代码是没有问题的, 剩下的就是看看协程怎么写...
from gevent import monkey
monkey.patch_all()
# 导入所需的库和模块:
import pymysql
import csv
import bs4
import requests
import gevent
from gevent.queue import Queue
sql_list = []
# 创建队列对象,并赋值给work。
work = Queue()
# 前3个常见食物分类的前3页的食物记录的网址:
url_1 = 'http://www.boohee.com/food/group/{type}?page={page}'
# 通过两个for循环,能设置分类的数字和页数的数字。
for x in range(1, 11):
    for y in range(1, 11):
        real_url = url_1.format(type=x, page=y)
        # 然后,把构造好的网址用put_nowait添加进队列里。
        work.put_nowait(real_url)
# 第11个常见食物分类的前3页的食物记录的网址:
url_2 = 'http://www.boohee.com/food/view_menu?page={page}'
# 通过for循环,能设置第11个常见食物分类的食物的页数。
for x in range(1, 11):
    real_url = url_2.format(page=x)
    # 然后,把构造好的网址用put_nowait添加进队
    work.put_nowait(real_url)
# 定义crawler函数
def crawler():
    # 添加请求头
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
    }
    # 当队列不是空的时候,就执行下面的程序。
    while not work.empty():
        # 用get_nowait()方法从队列里把刚刚放入的网址提取出来。
        url = work.get_nowait()
        # 用requests.get获取网页源代码。
        res = requests.get(url, headers=headers)
        # 用BeautifulSoup解析网页源代码。
        bs_res = bs4.BeautifulSoup(res.text, 'html.parser')
        # 获取当前分类
        category = bs_res.find('div',class_="widget-food-list pull-right").find('h3').text
        # 用find_all提取出<li class="item clearfix">标签的内容。
        foods = bs_res.find_all('li', class_='item clearfix')
        # 遍历foods
        for food in foods:
            # 用find_all在<li class="item clearfix">标签下,提取出第2个<a>元素title属性的值,也就是食物名称。
            food_name = food.find_all('a')[1]['title']
            # 用find在<li class="item clearfix">标签下,提取<p>元素,再用text方法留下纯文本,就提取出了食物的热量。
            food_calorie = food.find('p').text[3:]
            # 打印食物的名称。
            sql = "insert into food(category,name,calorie) values({},{},{})".format(repr(category), repr(food_name), repr(food_calorie))
            sql_list.append(sql)
# 创建空的任务列表
tasks_list = []
# 相当于创建了5个爬虫
for x in range(5):
    # 用gevent.spawn()函数创建执行crawler()函数的任务。
    task = gevent.spawn(crawler)
    # 往任务列表添加任务。
    tasks_list.append(task)
# 用gevent.joinall方法,启动协程,执行任务列表里的所有任务,让爬虫开始爬取网站。
gevent.joinall(tasks_list)
connection = pymysql.connect(user='root', password='root', db='boohee')
cursor = connection.cursor()
cursor.execute('drop database boohee')
cursor.execute('create database boohee character set utf8')
cursor.execute('use boohee')
cursor.execute('create table food(id int primary key auto_increment, category varchar(20) not null, name varchar(200) not null, calorie varchar(200) not null)')
connection.commit()
for sql in sql_list:
    cursor.execute(sql)
    connection.commit()
connection.close()
复制代码

快速跳转:

猫哥教你写爬虫 000--开篇.md
猫哥教你写爬虫 001--print()函数和变量.md
猫哥教你写爬虫 002--作业-打印皮卡丘.md
猫哥教你写爬虫 003--数据类型转换.md
猫哥教你写爬虫 004--数据类型转换-小练习.md
猫哥教你写爬虫 005--数据类型转换-小作业.md
猫哥教你写爬虫 006--条件判断和条件嵌套.md
猫哥教你写爬虫 007--条件判断和条件嵌套-小作业.md
猫哥教你写爬虫 008--input()函数.md
猫哥教你写爬虫 009--input()函数-人工智能小爱同学.md
猫哥教你写爬虫 010--列表,字典,循环.md
猫哥教你写爬虫 011--列表,字典,循环-小作业.md
猫哥教你写爬虫 012--布尔值和四种语句.md
猫哥教你写爬虫 013--布尔值和四种语句-小作业.md
猫哥教你写爬虫 014--pk小游戏.md
猫哥教你写爬虫 015--pk小游戏(全新改版).md
猫哥教你写爬虫 016--函数.md
猫哥教你写爬虫 017--函数-小作业.md
猫哥教你写爬虫 018--debug.md
猫哥教你写爬虫 019--debug-作业.md
猫哥教你写爬虫 020--类与对象(上).md
猫哥教你写爬虫 021--类与对象(上)-作业.md
猫哥教你写爬虫 022--类与对象(下).md
猫哥教你写爬虫 023--类与对象(下)-作业.md
猫哥教你写爬虫 024--编码&&解码.md
猫哥教你写爬虫 025--编码&&解码-小作业.md
猫哥教你写爬虫 026--模块.md
猫哥教你写爬虫 027--模块介绍.md
猫哥教你写爬虫 028--模块介绍-小作业-广告牌.md
猫哥教你写爬虫 029--爬虫初探-requests.md
猫哥教你写爬虫 030--爬虫初探-requests-作业.md
猫哥教你写爬虫 031--爬虫基础-html.md
猫哥教你写爬虫 032--爬虫初体验-BeautifulSoup.md
猫哥教你写爬虫 033--爬虫初体验-BeautifulSoup-作业.md
猫哥教你写爬虫 034--爬虫-BeautifulSoup实践.md
猫哥教你写爬虫 035--爬虫-BeautifulSoup实践-作业-电影top250.md
猫哥教你写爬虫 036--爬虫-BeautifulSoup实践-作业-电影top250-作业解析.md
猫哥教你写爬虫 037--爬虫-宝宝要听歌.md
猫哥教你写爬虫 038--带参数请求.md
猫哥教你写爬虫 039--存储数据.md
猫哥教你写爬虫 040--存储数据-作业.md
猫哥教你写爬虫 041--模拟登录-cookie.md
猫哥教你写爬虫 042--session的用法.md
猫哥教你写爬虫 043--模拟浏览器.md
猫哥教你写爬虫 044--模拟浏览器-作业.md
猫哥教你写爬虫 045--协程.md
猫哥教你写爬虫 046--协程-实践-吃什么不会胖.md
猫哥教你写爬虫 047--scrapy框架.md
猫哥教你写爬虫 048--爬虫和反爬虫.md
猫哥教你写爬虫 049--完结撒花.md

转载于:https://juejin.im/post/5cfc4adee51d4550bf1ae82e

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值