通過scrapy實現簡單爬蟲
Scrapy概述
網路爬蟲,大概很多人都聽說過吧。
它是通過一定的規則,自動抓取網際網路網站上的文章、資訊、圖片等等內容。
常見的應用就是搜尋引擎。
而Scrapy則是實現網路爬蟲的方式之一。
官方描述的Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。
可以應用在包括資料探勘,資訊處理或儲存歷史資料等一系列的程式中。
Scrapy安裝配置
Scrapy是需要配置Python環境的。所以我們先通過pycharm新建一個project。
配置git
然後安裝環境:
pip install scrapy
pycharm並不支援直接建立scrapy的project,所以我們需要手動建立:
scrapy startproject SpiderProject
建立模板
scrapy提供了命令讓我們可以根據模板建立spider,這個命令就是genspider
genspider可以直接建立spider的模板,比如我們爬www.ttsla.com:
scrapy genspider ttsla www.ttsla.com
可以通過scrapy genspider -h 檢視相關幫助
我們也可以通過scrapy genspider -l 檢視可用模板
如果是windows下還需要裝個win32模組:
pip install -i https://pypi.douban.com/simple pypiwin32
除錯執行
在命令列中除錯選擇器:
scrapy shell www.ttsla.com
這樣我們就可以很方便的在命令列中通過response.css除錯選擇器,並把正確的除錯結果copy到程式碼中。
實現簡單的爬蟲功能需要改三個檔案:
settings.py
items.py
ttlsa.py
settings.py下需要設定ROBOTSTXT_OBEY,否則會過濾掉不符合ROBOTS協議的url:
ROBOTSTXT_OBEY = False
settings.py中還需要配置ITEM_PIPELINES,這一段程式碼預設是禁用的:
ITEM_PIPELINES = { 'ttlsaSpider.pipelines.TtlsaspiderPipeline': 300, }
item.py中定義爬蟲爬取結果的結構,可以定義多個,比如標題定義類似於這種:
class TtlsaspiderItem(scrapy.Item):
title = scrapy.Field()
ttlsa.py這個是我自定義的蜘蛛的名字,名字也可以是其他的,我這裡只是示例。
如果我們之前執行了建立模板的命令,系統會自動生成這個檔案。
其中的parse函式需要自己來寫。要注意相互呼叫的關係。比如最簡單的:
def parse(self, response):
item = TtlsaspiderItem()
nodes = response.css(".entry-header .entry-title a")
item['標題'] = nodes.css("::text").extract()
yield item
注意在定義start_urls的時候,要配置好完整的url路徑:
start_urls = ['http://www.ttlsa.com']
配好這三個檔案,我們就可以scrapy crawl ttlsa -o result.csv來跑一下,
會自動生成一個csv檔案
開啟csv檔案來驗證結果。
取資料
通過網站的頁面取資料有兩種方法:xpath和css。
這兩種取資料的方式各有優缺點,可以根據實際情況來分別應用。
通過xpath取出資料,示例如下:
title = response.xpath('//*[@class="grid-8"]/div[1]/div[1]/h1/text()').extract()
通過css取資料,示例如下:
title = response.css(".entry-header .entry-title a::text").extract()
response.xpath會返回一個SelectorList物件,extract後會把selector物件轉換成list型別
如果取出來是一個list,可以通過selector[0]取出值.
xpath的值可以通過chrome瀏覽器的F12的除錯功能找,然後把xpath複製出來。
下面是複雜一些的,取日期,其實方法是一樣的:
date = response.xpath("//*[@class='entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·", "").strip()
strip()方法是去空格和換行符;replace()方法是替換。
contains,我們加上contains,就是class中包含了‘vote-post-up’這個字串就匹配了,程式碼如下:
response.xpath("//*[contains(@class, 'vote-post-up')]")
通常這種用法適合class包含了多個字串的時候進行匹配。
有些時候需要通過正則來匹配,以下程式碼我們用xpath通過正則過濾掉了中文,只保留數字:
comments_nums = response.xpath("//a[contains(@href, '#article-comment')]/span/text()").extract()[0].strip()
match_re = re.match(".*?(\d+).*", comments_nums)
if match_re:
comments_nums = match_re.group(1)
為了方便除錯,我們可以自定義一個main.py,效果和命令列裡輸入命令是一樣的:
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'ttlsa'])
export
資料生成以後我們可以匯出。我們需要修改pipelines.py的檔案,可以通過pipeline將資料儲存到json或資料庫等。
Json的匯出可以自定義方法,也可以使用自帶的JsonItemExporter方法:
#使用scrapy內建JsonItemExporter的方法輸出json
class JsonItemExporterPipeline(object):
def __init__(self):
self.file = open("result.json", "wb")
self.export = JsonItemExporter(self.file, ensure_ascii=False, encoding='utf8')
self.export.start_exporting()
def close_spider(self):
self.export.finish_exporting()
def process_item(self, item, spider):
self.export.export_item(item)
return item
匯出到資料庫的方法也是類似的,我們以MySQL為例。我們首先需要裝個mysqlclient
提供一個連結:
https://www.lfd.uci.edu/~gohlke/pythonlibs/#
這裡有非常多適配windows的python庫,搜一下mysql就能找出來,然後直接pip install
注意cp35代表python3.5的版本,win32代表32位的系統。
然後裝mysql建庫建表就不說了,我是直接用docker建庫。建好表以後,可以增加設定一個id欄位作為自增欄位。
編寫pipelines.py,新增自定義類,我這裡就只兩個欄位:
class MysqlPipelines(object):
def __init__(self):
self.conn = MySQLdb.connect(host="192.168.99.100", user="root", passwd="root", port=3316, db="article_spider", charset="utf8", use_unicode=True)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
insert_sql = """insert into ttlsa (title, url) values (%s, %s)"""
self.cursor.execute(insert_sql, (item["title"], item["url"]))
self.conn.commit()
注意修改settings.py裡的配置檔案
執行main.py除錯。