以美团烤肉为例,将爬取的数据进行保存。
第一种:csv。
新建一个csv文档,利用字典写入器写入头,然后把爬取好的数据进行字典构造,然后将字典逐条写入到csv文档里。
1 """ 2 爬取美团烤肉 3 """ 4 import pprint 5 import csv 6 import parsel 7 import requests 8 import json 9 10 f = open('美团烤肉.csv', mode='a', encoding='utf-8-sig', newline='') 11 csvWriter = csv.DictWriter(f, fieldnames=[ 12 '商铺id', 13 '商铺名称', 14 '烤肉类型', 15 '评论人数', 16 '平均消费', 17 '商铺评分', 18 '所在商圈', 19 '详情页', 20 ]) 21 csvWriter.writeheader() # 写入头 22 23 headers = { 24 'referer':'https://xxz.meituan.com/', # 这个叫防盗链,也叫来路,没有这个可能不会返回正常的json数据 25 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 26 } 27 28 29 for page in range(32, 620 + 1, 32): 30 # 原始请求url= https://apimobile.meituan.com/group/v4/poi/pcsearch/110?uuid=f7325d6be06f44019907.1639106132.1.0.0&userid=394536385&limit=32&offset=64&cateId=-1&q=烤肉&token=mKqO1rGk3adC-dG4fspmVCJj-bgAAAAAhA8AAPVPiOhDFB1UirWrXZHX_ZEM-6qsRE4yHPX1o2RbzI9csT0G-CikXFP8TPrDZj0EwQ 31 # url中?后面的都是参数,下面来构建参数 32 data = { 33 "uuid": "faf0.0", 34 "userid": "39e", 35 "limit": "32", 36 "offset": page, 37 "cateId": "-1", 38 "q": "烤肉", 39 "token": "xx", 40 } 41 url = 'https://apimobile.meituan.com/group/v4/poi/pcsearch/110' 42 # 构建好了参数,也有url,下面带参数进行请求 43 response = requests.get(url=url, headers=headers, params=data) # 携带参数是params,而不是data 44 results = response.json()['data']['searchResult'] 45 pprint.pprint(results) 46 for item in results: 47 shopId = item['id'] # 店铺id,用于构建详情页 48 shopName = item['title'] # 店名 49 comment = item['comments'] # 评论数 50 commentScore = item['avgscore'] # 评分 51 averagePrice = item['avgprice'] # 均价 52 shopStyle = item['backCateName'] # 烤肉类型 53 areaName = item['areaname'] # 所在地区 54 detailPage = 'https://www.meituan.com/meishi/' + str(shopId) 55 56 # if detailPage: # 如果有详情页,就把电话和地址还有营业时间提取出来 57 # res = requests.get(url=detailPage, headers=headers) 58 # print(res.text) 59 # selector = parsel.Selector(res.text) # 用parsel解析 60 # lis = selector.css('.address') 61 # for li in lis: 62 # address = li.css('p:nth-child(1)::text').get() 63 # telephone = li.css('p:nth-child(2)::text').get() 64 # businessTime = li.css('p:nth-child(3)::text').get() 65 print(shopId, shopName, shopStyle, comment, averagePrice, commentScore, areaName, detailPage, sep=' | ') 66 dit = { 67 '商铺id': shopId, 68 '商铺名称': shopName, 69 '烤肉类型': shopStyle, 70 '评论人数':comment, 71 '平均消费': averagePrice, 72 '商铺评分': commentScore, 73 '所在商圈': areaName, 74 '详情页': detailPage, 75 } 76 csvWriter.writerow(dit) # 写入数据 77 f.close() # 关闭文档
第二种:excel,利用openpyxl将数据保存成.xlsx格式的。
利用openpyxl创建一个工作簿,在工作簿里新建工作表,利用行列标签写入表头。然后将采集好的数据,逐条追加到表格。
1 import random 2 import time 3 import openpyxl 4 import json 5 import requests 6 7 wb = openpyxl.Workbook() # 新建工作簿 8 ws = wb.create_sheet(index=0) # 新建工作表 9 10 # 写入头 11 ws.cell(row=1, column=1, value='商铺id') # 第一行第一列写入商铺id 12 ws.cell(row=1, column=2, value='商铺名称') # 第一行第二列写入商铺名称 13 ws.cell(row=1, column=2, value='烤肉类型') # 第一行第二列写入商铺名称 14 ws.cell(row=1, column=2, value='评论人数') # 第一行第二列写入商铺名称 15 ws.cell(row=1, column=2, value='平均消费') # 第一行第二列写入商铺名称 16 ws.cell(row=1, column=2, value='商铺评分') # 第一行第二列写入商铺名称 17 ws.cell(row=1, column=2, value='所在商圈') # 第一行第二列写入商铺名称 18 ws.cell(row=1, column=2, value='详情页') # 第一行第二列写入商铺名称 19 20 # 数据爬取部分 21 headers = { 22 'referer':'https://xx.meituan.com/', # 这个叫防盗链,也叫来路,没有这个可能不会返回正常的json数据 23 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 24 } 25 headersfordetailPage = { 26 'cookie':'cookie', 27 'referer':'https://xx.meituan.com/', # 这个叫防盗链,也叫来路,没有这个可能不会返回正常的json数据 28 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 29 } 30 for page in range(32, 640 + 1, 32): 31 time.sleep(random.uniform(2, 5)) 32 data = { 33 "uuid": "efea", 34 "userid": "fafa", 35 "limit": "32", 36 "offset": page, 37 "cateId": "-1", 38 "q": "烤肉", 39 "token": "afaf", 40 } 41 url = 'https://apimobile.meituan.com/group/v4/poi/pcsearch/110' 42 # 请求数据 43 response = requests.get(url=url, headers=headersfordetailPage, params=data) 44 # 获取返回数据 45 results = response.json()['data']['searchResult'] # 找到需要的数据 46 for item in results: 47 shopId = item['id'] # 店铺id,用于构造详情页 48 shopName = item['title'] # 店名 49 comment = item['comments'] # 评论数 50 commentScore = item['avgscore'] # 评分 51 averagePrice = item['avgprice'] # 均价 52 shopStyle = item['backCateName'] # 烤肉类型 53 areaName = item['areaname'] # 所在地区 54 detailPage = 'https://www.meituan.com/meishi/' + str(shopId) 55 56 print(shopId, shopName, comment, commentScore, averagePrice, shopStyle, areaName, detailPage, sep=" | ") 57 ws.append([shopId, shopName, comment, commentScore, averagePrice, shopStyle, areaName, detailPage]) # 写入到表格 58 59 wb.close() # 关闭文档
第三种,使用pandas保存数据到本地,可以是csv文件也可以是xlsx文件。
1 import random 2 import time 3 4 import pandas as pd 5 import requests 6 import json 7 8 df = pd.DataFrame() # DataFrame数据格式,用于保存到本地 9 10 headers = { 11 'referer':'https://qz.meituan.com/', # 这个叫防盗链,也叫来路,没有这个可能不会返回正常的json数据 12 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 13 } 14 15 for page in range(32, 640 + 1, 32): 16 print(f'-------------------------正在爬取第{int(page/32)}页数据------------------------------') 17 time.sleep(random.uniform(2,5)) # 随机休眠 18 # 请求参数 19 data = { 20 "uuid": "id", 21 "userid": "fd", 22 "limit": "32", 23 "offset": page, 24 "cateId": "-1", 25 "q": "烤肉", 26 "token": "ddd", 27 } 28 # 请求网址 29 url = 'https://apimobile.meituan.com/group/v4/poi/pcsearch/110' 30 # 开始请求数据 31 response = requests.get(url=url, headers=headers, params=data) # 带参数请求网页 32 results = response.json()['data']['searchResult'] # 取到列表数据 33 for item in results: 34 shopId = item['id'] # 店铺id,用于构造详情页 35 shopName = item['title'] # 店名 36 comment = item['comments'] # 评论数 37 commentScore = item['avgscore'] # 评分 38 averagePrice = item['avgprice'] # 均价 39 shopStyle = item['backCateName'] # 烤肉类型 40 areaName = item['areaname'] # 所在地区 41 detailPage = 'https://www.meituan.com/meishi/' + str(shopId) 42 print(shopId, shopName, comment, commentScore, averagePrice, shopStyle, areaName, detailPage, sep=" | ") 43 data = pd.DataFrame({'商铺id':[shopId], '商铺名称':[shopName], '评论人数':[comment], '平均评分':[commentScore], 44 '平均价格':[averagePrice], '烤肉类型':[shopStyle], '商铺商圈':[areaName], '详情页':[detailPage]}) 45 df = pd.concat([df, data]) # 连接数据 46 # df.to_csv('美团烤肉pd.csv', encoding='utf-8-sig', index=False, mode='a') # 保存到csv 47 df.to_excel('美团烤肉pd.xlsx', encoding='utf-8-sig', index=False) # 保存到excel
第四种,保存到MySql数据库:
首先在服务器创建数据库,我一般用phpmyadmin控制台和navicat创建数据库。新建数据库的时候,最好用navicat新建,选的字符utf8 -- UTF-8 Unicode,在phpmyadmin里建utf8_general_ci字符集。
创建完数据库后进行数据表设计,表名为meituandata。字段为店铺id,店铺名,评论人数,平均评分,平均消费,烤肉类型,所在商圈,详情页,sql语句如下:
1 CREATE TABLE `20211214meituan`.`meituandata` 2 ( 3 `id` INT NOT NULL AUTO_INCREMENT COMMENT '自增id' , 4 `shopId` INT NOT NULL COMMENT '商铺id' , 5 `shopName` VARCHAR(30) NOT NULL COMMENT '商铺名' , 6 `commentCount` INT NOT NULL COMMENT '评论人数取整数' , 7 `avgScore` FLOAT NOT NULL COMMENT '平均分' , 8 `avgPrice` DECIMAL NOT NULL COMMENT '消费均价' , 9 `shopStyle` VARCHAR(30) NOT NULL COMMENT '烤肉类型' , 10 `shopArea` VARCHAR(255) NOT NULL COMMENT '所在商圈' , 11 PRIMARY KEY (`id`) 12 ) ENGINE = MyISAM;
创建完后发现少了一个字段,在加一个字段,sql语句:
1 ALTER TABLE `meituandata` ADD `detailPage` VARCHAR(255) NOT NULL AFTER `shopArea`;
爬虫加保存代码:
1 import random 2 import time 3 import requests 4 import json 5 import pymysql 6 7 # 首先是爬虫 8 headers = { 9 'cookie':'YourCookie', 10 'referer':'https://xx.meituan.com/', 11 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36', 12 } 13 14 for offset in range(0, 640 + 1, 32): # 15 data = { 16 "uuid": "YourId", 17 "userid": "Id", 18 "limit": "32", 19 "offset": offset, 20 "cateId": "-1", 21 "q": "keywords", 22 "token": "YourToken", 23 } 24 # 美团的数据也是存储在json里的,只是前两页没有数据 25 time.sleep(random.uniform(2,8)) 26 url = 'https://apimobile.meituan.com/group/v4/poi/pcsearch/110' 27 response = requests.get(url=url, headers=headers,params=data) 28 # print(response.json()) 29 # 从json中获取我们要的结果 30 results = response.json()['data']['searchResult'] # 结果 31 for item in results: 32 shopId = int(item['id']) # 商铺id 33 shopName = str(item['title']) # 商铺名字 34 commentCount = int(item['comments']) # 评论数 35 avgCommentScore = float(item['avgscore']) # 店铺评论平均分 36 avgPrice = float(item['avgprice']) # 店铺人均消费 37 shopStyle = str(item['backCateName']) # 烤肉类型 38 shopArea = str(item['areaname']) # 店铺商圈 39 detailPage = 'https://www.meituan.com/meishi/{}/'.format(shopId) 40 print(shopId, shopName, commentCount, avgCommentScore, avgPrice, shopStyle, shopArea, detailPage, sep=' | ') 41 # 定义数据库常数 42 # host = '127.0.0.1' # 数据库服务器地址 43 # user = 'root' # 数据库用户名 44 # pwd = '' # 数据库密码 45 # dbname = 'meituan', # 数据库名称 46 # 开始连接数据库 47 database = pymysql.connect(host='127.0.0.1', user='root', password='', database='meituan', charset='utf8') 48 # 建立游标对象 49 cursor = database.cursor() 50 # sql语句 51 sql = "INSERT INTO meituandata (shopId, shopName, commentCount, avgScore, avgPrice, shopStyle, shopArea, detailPage) " \ 52 "VALUES ('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}');".format(shopId, shopName, commentCount, avgCommentScore, avgPrice, shopStyle, shopArea, detailPage) 53 # 执行sql语句 54 cursor.execute(sql) 55 # 执行数据库更改 56 database.commit() 57 database.close() # 在所有数据写入之后关闭数据库
程序运行结果截图:
数据保存记录截图:
总结几个坑:
1,爬虫呢,如果找不到动态数据,可以用selenium进行渲染网页后进行提取信息;
2,sql语句与python结合呢,不能用f"stringxxxxx",只能用"stringxxxx{}".format(),要不然sql语句会一直报错,1064最多,1064是语法错误;
3,用pymysql连接数据库的时候,charset是utf8,不是utf-8;
4,做爬虫已经很惹人厌了,本人提倡请求页面的时候有时间间隔,给服务器减压。
5,最后,本文仅供学习交流使用,也是本人的笔记之一,如有疑问,请与我联系,我将即时处理。