【汽車口碑分析】3.爬取汽車評論資料
阿新 • • 發佈:2019-02-14
環境配置
- Ubuntu 16.04
- Python 3.5
技術框架
- Scrapy
需求目標
本專案為汽車口碑分析,第一步需要爬取對於不同車型的評論資料。
選擇58車的車型分類爬取評論資料。
爬取流程
先獲取每個車型的連結,以下圖中紅框內的車型為例
開啟連結後,抓取下圖紅框中的總評分,寫入檔案中。
寫入總評分後,通過拼接連結進入該車型的使用者評論頁面。
通過第一步中獲取的連結拼接上
list_s1_p1.html
,組成使用者評論頁面的連結。【注】此為第一頁的連結,若還有下一頁,下述步驟會提及處理方法。
抓取評論頁面中的各種資料,如
id
,評分
評論
等。若該評論頁面還有
下一頁
,則繼續抓取下一頁中的評論資料。【方法】
判斷頁面中是否有
下一頁
元素,若有則回撥解析評論頁面的方法。將爬取的資料儲存到檔案中。
詳細步驟
建立新工程
先建立工程目錄
cd /home/t/dataset/
mkdir carSpider
建立新工程
scrapy startproject carSpider
編輯items.py
檔案
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class CarspiderItem(scrapy.Item):
file=scrapy.Field() #檔名
car=scrapy.Field() #車型
score=scrapy.Field() #總評分
u_id=scrapy.Field() #使用者ID
u_score=scrapy.Field() #使用者評分
u_merit=scrapy.Field() #使用者評論優點
u_demerit=scrapy.Field() #使用者評論缺點
u_summary=scrapy.Field() #使用者評論綜述
u_flower=scrapy.Field() #使用者評論鮮花數
u_brick=scrapy.Field() #使用者評論板磚數
編寫carSpider.py
檔案
import scrapy
from carSpider.items import CarspiderItem
baseDir = '/home/t/dataset/carRemark/'
startUrl='http://www.58che.com/brand.html'
class CarSpider(scrapy.Spider):
name='spider' #爬蟲名
def __init__(self):
self.start_urls=[startUrl]
#第一層解析方法
def parse(self,response):
#定位到車型元素
subclasses=response.css('body > div.fltop > div.marcenter > div > div > div.r > ul > li > dl > dt > a')
for subclass in subclasses:
subclass_name=subclass.xpath('text()').extract_first() #獲取車型名稱文字
subclass_link=subclass.xpath('@href').extract_first() #獲取車型連結
yield scrapy.Request(url=subclass_link,callback=self.parse_car_subclass,meta={'file':subclass_name}) #回撥下一層解析方法,並把車型名稱傳遞給該方法作為檔名
#第二層解析方法
def parse_car_subclass(self,response):
infos=response.css('#line1 > div.cars_line2.l > div.dianpings > div.d_div1.clearfix > font') #定位到總評分元素
for info in infos:
score=info.xpath('text()').extract_first() #獲取總評分元素文字
file=response.meta['file'] #獲取上個Request傳遞來的meta['file']
self.writeScore(file,score) #將總評分寫入檔案中
link=response.url+'list_s1_p1.html' #拼接使用者評論第一頁連結
yield scrapy.Request(url=link,callback=self.parse_remark,meta={'file':file}) #回撥下一層解析方法,把車型名稱傳遞給該方法作為檔名
#第三層解析方法
def parse_remark(self,response):
#定位到使用者評論元素
infos=response.css('body > div.newbox > div > div.xgo_cars_w760.l > div.xgo_dianping_infos.mb10 > div.xgo_cars_dianping > div > dl')
for info in infos:
uid=info.xpath('dd[1]/strong/a/text()')[0].extract() #獲取使用者ID
score=info.xpath('dd[1]/div/div/@style')[0].extract() #獲取使用者評分星級
score=self.getScore(score) #將使用者評分星級轉化為5分制評分
try:
#先獲取是否有‘優點’元素,若有則定位‘優點’元素的下一個兄弟節點,即‘優點評語’,若無則為空
node=info.xpath('dd[2]/div/div[contains(@class,"l redc00")]')[0]
if node is not None:
merit=node.xpath('following-sibling::*[1]/text()')[0].extract()
else:
merit=''
except:
merit=''
try:
#先獲取是否有‘缺點’元素,若有則定位‘缺點’元素的下一個兄弟節點,即‘缺點評語’,若無則為空
node=info.xpath('dd[2]/div/div[contains(@class,"l hei666")]')[0]
if node is not None:
demerit=node.xpath('following-sibling::*[1]/text()')[0].extract()
else:
demerit=''
except:
demerit=''
try:
#先獲取是否有‘綜述’元素,若有則定位‘綜述’元素的下一個兄弟節點,即‘綜述評語’,若無則為空
node=info.xpath('dd[2]/div/div[contains(@class,"l")]')[0]
if node is not None:
summary=node.xpath('following-sibling::*[1]/text()')[0].extract()
else:
summary=''
except:
summary=''
flower=info.xpath('dd[2]/div[contains(@class,"apply")]/a[3]/span/text()')[0].extract() #獲取鮮花數
brick=info.xpath('dd[2]/div[contains(@class,"apply")]/a[4]/span/text()')[0].extract() #獲取板磚數
#建立Item
item=CarspiderItem()
item['file']=response.meta['file']
item['u_id']=uid
item['u_score']=score
item['u_merit']=merit
item['u_demerit']=demerit
item['u_summary']=summary
item['u_flower']=flower
item['u_brick']=brick
#生成Item
yield item
#獲取`下一頁`元素,若有則回撥`parse_remark`第三層解析方法,即繼續獲取下一頁使用者評論資料
#定位`下一頁`元素
next_pages=response.css('body > div.newbox > div > div.xgo_cars_w760.l > div.xgo_dianping_infos.mb10 > div.xgo_cars_dianping > div > div > a.next')
for next_page in next_pages:
#若有`下一頁`元素,則拼接`下一頁`元素連結,並回調第三層解析方法,用來獲取下一頁使用者評論資料
if next_page is not None:
next_page_link=next_page.xpath('@href')[0].extract()
next_page_link='http://www.58che.com'+next_page_link
file=response.meta['file']
yield scrapy.Request(url=next_page_link, callback=self.parse_remark, meta={'file': file})
#將總評分寫入檔案
def writeScore(self,file,score):
with open('/home/t/dataset/carRemark/'+file+'.json','a+') as f:
f.write(score+'\n')
#將使用者評分星級轉為5分制分數,類似switch功能
def getScore(self,text):
text=text.split(':')[1] #分割文字,原文字格式形如`width:100%`,分割並擷取`:`後的文字
return {
'100%':5,
'80%':4,
'60%':3,
'40%':2,
'20%':1,
'0%':0
}.get(text)
【解析】
#定位到使用者評論元素
infos=response.css('body > div.newbox > div > div.xgo_cars_w760.l > div.xgo_dianping_infos.mb10 > div.xgo_cars_dianping > div > dl')
此句程式碼定位的元素如下圖所示,定位到的是評論頁面每條評論的元素整體。
for info in infos:
uid=info.xpath('dd[1]/strong/a/text()')[0].extract() #獲取使用者ID
score=info.xpath('dd[1]/div/div/@style')[0].extract() #獲取使用者評分星級
score=self.getScore(score) #將使用者評分星級轉化為5分制評分
uid
定位到的元素如下圖所示,
score
定位到的元素如下圖所示,獲取score
元素的style
屬性,值形如width:80%
,需要通過getScore()
方法轉換為五分制分數。
try:
#先獲取是否有‘優點’元素,若有則定位‘優點’元素的下一個兄弟節點,即‘優點評語’,若無則為空
node=info.xpath('dd[2]/div/div[contains(@class,"l redc00")]')[0]
if node is not None:
merit=node.xpath('following-sibling::*[1]/text()')[0].extract()
else:
merit=''
except:
merit=''
先定位是否有優點
元素,如下圖紅框所示,若有該元素,則獲取優點
元素的下一個兄弟節點內容,如下圖藍框所示,若無則為空。
#獲取`下一頁`元素,若有則回撥`parse_remark`第三層解析方法,即繼續獲取下一頁使用者評論資料
#定位`下一頁`元素
next_pages=response.css('body > div.newbox > div > div.xgo_cars_w760.l > div.xgo_dianping_infos.mb10 > div.xgo_cars_dianping > div > div > a.next')
for next_page in next_pages:
#若有`下一頁`元素,則拼接`下一頁`元素連結,並回調第三層解析方法,用來獲取下一頁使用者評論資料
if next_page is not None:
next_page_link=next_page.xpath('@href')[0].extract()
next_page_link='http://www.58che.com'+next_page_link
file=response.meta['file']
yield scrapy.Request(url=next_page_link, callback=self.parse_remark, meta={'file': file})
解析完上述內容,判斷使用者評論頁面是否有分頁,定位是否有下一頁
元素,如下圖紅框所示,若有則獲取該元素連結,如下圖橙框所示。
獲取之後,回撥parse_remark
方法解析下一頁的評論頁面。
編輯pipelines.py
檔案
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
import codecs
baseDir = '/home/t/dataset/carRemark/'
class CarspiderPipeline(object):
def process_item(self, item, spider):
print(item['file'])
with codecs.open(baseDir+item['file']+'.json','a+',encoding='utf-8') as f:
line=json.dumps(dict(item),ensure_ascii=False)+'\n'
f.write(line)
return item
編輯settings.py
檔案
# -*- coding: utf-8 -*-
# Scrapy settings for carSpider project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# http://doc.scrapy.org/en/latest/topics/settings.html
# http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
# http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'carSpider'
SPIDER_MODULES = ['carSpider.spiders']
NEWSPIDER_MODULE = 'carSpider.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'carSpider (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# Enable or disable spider middlewares
# See http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'carSpider.middlewares.CarspiderSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'carSpider.middlewares.MyCustomDownloaderMiddleware': 543,
#}
# Enable or disable extensions
# See http://scrapy.readthedocs.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'carSpider.pipelines.CarspiderPipeline': 300,
}
# Enable and configure the AutoThrottle extension (disabled by default)
# See http://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
HTTPCACHE_ENABLED = False
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
【解析】
ROBOTSTXT_OBEY = False
將原來的True
改為False
。
ITEM_PIPELINES = {
'carSpider.pipelines.CarspiderPipeline': 300,
}
將原來的註釋去掉,即註冊pipelines,否則無法使用該pipelines。
執行爬蟲
在專案根目錄下新建檔案entrypoint.py
from scrapy.cmdline import execute
execute(['scrapy','crawl','spider'])