以美團烤肉為例,將爬取的數據進行保存。
第一種: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,最后,本文僅供學習交流使用,也是本人的筆記之一,如有疑問,請與我聯系,我將即時處理。