使用python创建爬虫非常简单: Meituan.com数据采集技能,如果您有基础,就开始爬网!
优采云 发布时间: 2020-08-08 14:491. 数据采集工具简介
如今,大多数动态网站通过浏览器端的js发起ajax请求,然后在接收到数据后呈现页面. 在这种情况下,采集数据,通过脚本启动http获取请求以及在获取DOM文档页面之后解析和提取有用数据的方法是不可行的. 然后有人会想到通过F12打开浏览器控制台来分析服务器api,然后模拟请求相应的api以获取我们想要的数据. 这个想法在某些情况下是可行的,但是许多大型网站都会采用一些防爬网策略,出于安全考虑,通常会在界面中添加安全验证. 例如,在请求页面之前,只能请求相关的标头和cookie. 有些还限制了请求的来源,等等,这一次通过这种方式采集数据就更加困难了. 我们还有其他有效的方法吗?当然,python爬虫非常简单,让我们首先了解Selenium和Selectors,然后通过抓取美团在线业务信息的示例总结一些数据采集技术:
2. 页面抓取数据分析和数据表创建
以朝阳大悦城的一家美食餐厅为数据采集示例,该网站为:
https://www.meituan.com/meishi/40453459/
2.1获取数据
我们要捕获的数据的第一部分是企业的基本信息,包括企业名称,地址,电话号码和营业时间. 在分析了多个美食企业之后,我们知道这些企业的Web界面在布局上基本相同. 因此我们的采集器可以编写更通用的内容. 为了防止重复抓取业务数据,我们还将业务的URL信息存储在数据表中.
第二部分要捕获的数据是美食餐厅的招牌菜. 每个商店基本上都有自己的特色菜. 我们还将保存这些数据并将其存储在另一个数据表中.
我们要捕获的数据的最后一部分是用户评论. 这部分数据对我们来说非常有价值. 将来,我们可以分析这部分数据以提取有关业务的更多信息. 我们要获取的信息的这一部分包括: 评论者的昵称,星级,评论内容,评论时间,如果有图片,我们还需要以列表的形式保存图片的地址.
2.2创建数据表
我们用来存储数据的数据库是Mysql,Python有一个相关的ORM,我们在项目中使用了peewee. 但是,建议在创建数据表时使用本机SQL,以便我们可以灵活地控制字段属性,设置引擎和字符编码格式等. 使用Python的ORM也可以实现结果,但是ORM是数据库层的封装,例如sqlite,sqlserver数据库和Mysql,仍然存在一些差异,使用ORM只能使用这些数据库的公共部分. 以下是存储数据所需的数据表sql:
CREATE TABLE `merchant` ( #商家表
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL COMMENT '商家名称',
`address` varchar(255) NOT NULL COMMENT '地址',
`website_address` varchar(255) NOT NULL COMMENT '网址',
`website_address_hash` varchar(32) NOT NULL COMMENT '网址hash',
`mobile` varchar(32) NOT NULL COMMENT '电话',
`business_hours` varchar(255) NOT NULL COMMENT '营业时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `recommended_dish` ( #推荐菜表
`id` int(11) NOT NULL AUTO_INCREMENT,
`merchant_id` int(11) NOT NULL COMMENT '商家id',
`name` varchar(255) NOT NULL COMMENT '推荐菜名称',
PRIMARY KEY (`id`),
KEY `recommended_dish_merchant_id` (`merchant_id`),
CONSTRAINT `recommended_dish_ibfk_1` FOREIGN KEY (`merchant_id`) REFERENCES `merchant` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=309 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `evaluate` ( #评论表
`id` int(11) NOT NULL AUTO_INCREMENT,
`merchant_id` int(11) NOT NULL COMMENT '商家id',
`user_name` varchar(255) DEFAULT '' COMMENT '评论人昵称',
`evaluate_time` datetime NOT NULL COMMENT '评论时间',
`content` varchar(10000) DEFAULT '' COMMENT '评论内容',
`star` tinyint(4) DEFAULT '0' COMMENT '星级',
`image_list` varchar(1000) DEFAULT '' COMMENT '图片列表',
PRIMARY KEY (`id`),
KEY `evaluate_merchant_id` (`merchant_id`),
CONSTRAINT `evaluate_ibfk_1` FOREIGN KEY (`merchant_id`) REFERENCES `merchant` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8427 DEFAULT CHARSET=utf8mb4;
相应地,我们还可以使用Python的ORM创建管理数据表. 稍后在分析代码时,我们将讨论peewee在mysql数据库上的一些常见操作,例如查询数据,插入数据库数据和返回id. 批量插入数据库等,读者可以采集相关材料并进行系统学习.
meituan_spider / models.py代码:
from peewee import *
# 连接数据库
db = MySQLDatabase("meituan_spider", host="127.0.0.1", port=3306, user="root", password="root", charset="utf8")
class BaseModel(Model):
class Meta:
database = db
# 商家表,用来存放商家信息
class Merchant(BaseModel):
id = AutoField(primary_key=True, verbose_name="商家id")
name = CharField(max_length=255, verbose_name="商家名称")
address = CharField(max_length=255, verbose_name="商家地址")
website_address = CharField(max_length=255, verbose_name="网络地址")
website_address_hash = CharField(max_length=32, verbose_name="网络地址的md5值,为了快速索引")
mobile = CharField(max_length=32, verbose_name="商家电话")
business_hours = CharField(max_length=255, verbose_name="营业时间")
# 商家推荐菜表,存放菜品的推荐信息
class Recommended_dish(BaseModel):
merchant_id = ForeignKeyField(Merchant, verbose_name="商家外键")
name = CharField(max_length=255, verbose_name="推荐菜名称")
# 用户评价表,存放用户的评论信息
class Evaluate(BaseModel):
id = CharField(primary_key=True)
merchant_id = ForeignKeyField(Merchant, verbose_name="商家外键")
user_name = CharField(verbose_name="用户名")
evaluate_time = DateTimeField(verbose_name="评价时间")
content = TextField(default="", verbose_name="评论内容")
star = IntegerField(default=0, verbose_name="评分")
image_list = TextField(default="", verbose_name="图片")
if __name__ == "__main__":
db.create_tables([Merchant, Recommended_dish, Evaluate])
3. 代码实现和详细说明
代码相对简单,但是要运行代码,您需要安装上述工具包: 还需要安装硒,scrapy和peewee,这些软件包可以通过pip来安装;另外,还需要安装selenium驱动程序浏览器相应的驱动程序,因为我在本地使用chrome浏览器,所以我下载了相关版本的chromedriver,将在以后使用. 要求读者检查使用python操作硒所需的准备工作,并手动设置相关环境. 接下来,详细分析代码;源代码如下:
<p>from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
from scrapy import Selector
from models import *
import hashlib
import os
import re
import time
import json
chrome_options = Options()
# 设置headless模式,这种方式下无启动界面,能够加速程序的运行
# chrome_options.add_argument("--headless")
# 禁用gpu防止渲染图片
chrome_options.add_argument('disable-gpu')
# 设置不加载图片
chrome_options.add_argument('blink-settings=imagesEnabled=false')
# 通过页面展示的像素数计算星级
def star_num(num):
numbers = {
"16.8": 1,
"33.6": 2,
"50.4": 3,
"67.2": 4,
"84": 5
}
return numbers.get(num, 0)
# 解析商家内容
def parse(merchant_id):
weblink = "https://www.meituan.com/meishi/{}/".format(merchant_id)
# 启动selenium
browser = webdriver.Chrome(executable_path="/Users/guozhaoran/python/tools/chromedriver", options=chrome_options)
browser.get(weblink)
# 不重复爬取数据
hash_weblink = hashlib.md5(weblink.encode(encoding='utf-8')).hexdigest()
existed = Merchant.select().where(Merchant.website_address_hash == hash_weblink)
if (existed):
print("数据已经爬取")
os._exit(0)
time.sleep(2)
# print(browser.page_source) #获取到网页渲染后的内容
sel = Selector(text=browser.page_source)
# 提取商家的基本信息
# 商家名称
name = "".join(sel.xpath("//div[@id='app']//div[@class='d-left']//div[@class='name']/text()").extract()).strip()
detail = sel.xpath("//div[@id='app']//div[@class='d-left']//div[@class='address']//p/text()").extract()
address = "".join(detail[1].strip())
mobile = "".join(detail[3].strip())
business_hours = "".join(detail[5].strip())
# 保存商家信息
merchant_id = Merchant.insert(name=name, address=address, website_address=weblink,
website_address_hash=hash_weblink, mobile=mobile, business_hours=business_hours
).execute()
# 获取推荐菜信息
recommended_dish_list = sel.xpath(
"//div[@id='app']//div[@class='recommend']//div[@class='list clear']//span/text()").extract()
# 遍历获取到的数据,批量插入数据库
dish_data = [{
'merchant_id': merchant_id,
'name': i
} for i in recommended_dish_list]
Recommended_dish.insert_many(dish_data).execute()
# 也可以遍历list,一条条插入数据库
# for dish in recommended_dish_list:
# Recommended_dish.create(merchant_id=merchant_id, name=dish)
# 查看链接一共有多少页的评论
page_num = 0
try:
page_num = sel.xpath(
"//div[@id='app']//div[@class='mt-pagination']//ul[@class='pagination clear']//li[last()-1]//span/text()").extract_first()
page_num = int("".join(page_num).strip())
# page_num = int(page_num)
except NoSuchElementException as e:
print("改商家没有用户评论信息")
os._exit(0)
# 当有用户评论数据,每页每页的读取用户数据
if (page_num):
i = 1
number_pattern = re.compile(r"\d+\.?\d*")
chinese_pattern = re.compile(u"[\u4e00-\u9fa5]+")
illegal_str = re.compile(u'[^0-9a-zA-Z\u4e00-\u9fa5.,,。?“”]+', re.UNICODE)
while (i