Python 新手入門不少時候都會寫個爬蟲練手,本教程使用 Scrapy 框架,幫你簡單快速實現爬蟲,並將數據保存至數據庫。在機器學習中數據挖掘也是十分重要的,個人數據科學老師曾經說過,好算法不如好數據。mysql
Scrapy ,Python 開發的一個快速、高層次的屏幕抓取和 web 抓取框架,用於抓取 web 站點並從頁面中提取結構化的數據。文件結構清晰,即便是小白也可以快速上手,總之很是好用😂。git
XPath ,它是一種用來查找 XML 文檔中節點位置的語言。 XPath 基於 XML 的樹狀結構,有不一樣類型的節點,包括元素節點,屬性節點和文本節點,提供在數據結構樹中找尋節點的能力。github
MySQL 是一種關係數據庫管理系統,它的優點:它是免費的。做者是下載了 MAMP for Mac ,內嵌MySQL
和Apache
。web
首先經過 Scrapy 爬取到網頁後, 經過 XPath 來定位指定元素,獲取到你想要的數據,獲得數據以後能夠將數據存入數據庫( MySQL )。簡單瞭解以後就能夠開始編寫你的爬蟲。算法
*重要:下載並查看 Demo ,結合本文能夠快速實現一個基本爬蟲✌️。sql
安裝 Scrapy (系統默認安裝了 Python)
:數據庫
$ pip install Scrapy
複製代碼
在當前目錄新建工程json
$ scrapy startproject yourproject
複製代碼
新建工程文件結構以下:瀏覽器
yourproject/
----|scrapy.cfg # 部署配置文件
|yourproject/ # 工程目錄
|----__init__.py
|----items.py # 項目數據文件
|----pipelines.py # 項目管道文件
|----settings.py # 項目設置文件
|----spiders/ # 咱們的爬蟲 目錄
|----__init__.py # 爬蟲主要代碼在這裏
複製代碼
簡單的爬蟲主要使用了spiders
、items
、pipelines
這三個文件:bash
先看看咱們要爬取的網站,這個是 Scrapy 官方 Demo 爬取數據用的網站,咱們先用這個來練手。
分析網頁的信息咱們能夠看到網頁主體是一個列表,列表每一行都包含可一句引用、做者名字、標籤等信息。做者名右邊點擊(about)能夠看到做者的詳細信息,包括介紹、出生年月日、地點等等。根據上面的數據,咱們能夠先建立以下數據模型:
items.py
import scrapy
# quote 咱們要爬取的主體
class QuoteItem(scrapy.Item):
text = scrapy.Field()
tags = scrapy.Field()
author = scrapy.Field()
next_page = scrapy.Field()
pass
# quote 的做者信息 對應 QuoteItem.author
class AuthorItem(scrapy.Item):
name = scrapy.Field()
birthday = scrapy.Field()
address = scrapy.Field()
description = scrapy.Field()
pass
複製代碼
全部的模型必須繼承scrapy.Item
,完成這一步咱們就能夠開始寫爬蟲的邏輯了。
# 完整的 QuoteItem 數據結構示例
{
text,
tags,
author:{
name,
birthday,
address,
description
}
}
複製代碼
既然是爬蟲,天然須要去爬取網頁,爬蟲部分的幾個要點:
scrapy.Spider
。name
,啓動爬蟲時要用。start_requests()
,做爲爬蟲的起點。parse()
中解析。spiders/init.py
import scrapy
from ScrapySample.items import QuoteItem
from ScrapySample.items import AuthorItem
複製代碼
name
->爬蟲名字,allowed_domains
->爬取網頁的白名單。class QuotesSpider(scrapy.Spider):
name = "quotes"
allowed_domains = ["quotes.toscrape.com"]
複製代碼
在start_requests()
中記錄你要爬取的網址。
能夠只放入一個網址,而後讓爬蟲本身爬取起始網址中下一頁的連接。也能夠在這裏把全部須要爬的網址直接放入,好比說page
通常是從1開始,而且有序的,寫一個for
循環能夠直接輸入全部頁面的網址。
本文使用的是讓爬蟲本身去爬取下一頁網址的方式,因此只寫入了一個起始網址。
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
複製代碼
以下代碼,爬取網頁成功以後,咱們要分析網頁結構,找到咱們須要的數據。
咱們先來看XPath語法,//div[@class="col-md-8"]/div[@class="quote"
:這是表示查找 class 爲"col-md-8"
的 div 節點下的一個子節點,而且子節點是一個 class 爲"quote"
div 節點。若是在當前頁面找到了這樣一個節點,則返回節點信息,若是沒有找到則返回None
。
def parse(self, response):
# 經過查看器,找到列表所在的節點
courses = response.xpath('//div[@class="col-md-8"]/div[@class="quote"]')
for course in courses:
# 將數據模型實例化 並從節點中找到數據填入咱們的數據模型
item = QuoteItem()
# 輪詢 course 節點下全部 class 爲 "text" 的 span 節點,獲取全部匹配到的節點的 text() ,因爲獲取到的是列表,咱們默認取第一個。
item['text'] = course.xpath('.//span[@class="text"]/text()').extract_first()
item['author'] = course.xpath('.//small[@class="author"]/text()').extract_first()
item['tags'] = course.xpath('.//div[@class="tags"]/a/text()').extract()
# 請求做者詳細信息
author_url = course.xpath('.//a/@href').extract_first()
# 若是做者介紹的連接不爲空 則去請求做者的詳細信息
if author_url != '':
request = scrapy.Request(url='http://quotes.toscrape.com'+author_url, dont_filter=True, callback=self.authorParse)
# 將咱們已經獲取到的 QuoteItem 傳入該請求的回調函數 authorParse(),在該函數內繼續處理做者相關數據。
request.meta['item'] = item
yield request
# 繼續爬向下一頁 該函數具體實現下面會分析
next_page_request = self.requestNextPage(response)
yield next_page_request
複製代碼
這段註釋不是很詳細,若是看不懂可能須要補一下相關知識。
爬取做者詳細信息
成功獲取做者詳細信息 AuthorItem 後而且賦值給 QuoteItem 的屬性 author
,這樣一個完整的引述信息 QuoteItem 就組裝完成了。
def authorParse(self, response):
# 先獲取從 parse() 傳遞過來的 QuoteItem
item = response.meta['item']
# 經過查看器,找到做者詳細信息所在節點
sources = response.xpath('//div[@class="author-details"]')
# 實例化一個做者信息的數據模型
author_item = AuthorItem()
# 往做者信息模型填入數據
for source in sources:
author_item['name'] = source.xpath('.//h3[@class="author-title"]/text()').extract_first()
author_item['birthday'] = source.xpath('.//span[@class="author-born-date"]/text()').extract_first()
author_item['address'] = source.xpath('.//span[@class="author-born-location"]/text()').extract_first()
author_item['description'] = source.xpath('.//div[@class="author-description"]/text()').extract_first()
# 最後將做者信息 author_item 填入 QuoteItem
item['author'] = author_item
# 保存組裝好的完整數據模型
yield item
複製代碼
爬蟲本身找到出路(下一頁網頁連接)
經過查看器咱們能夠找到下一頁
按鈕元素,找到該節點並提取連接,爬蟲即奔向下一個菜園。
def requestNextPage(self, response):
next_page = response.xpath('.//li[@class="next"]/a/@href').extract_first()
# 判斷下一個是按鈕元素的連接是否存在
if next_page is not None:
if next_page != '':
return scrapy.Request(url='http://quotes.toscrape.com/'+next_page, callback=self.parse)
return None
複製代碼
爬蟲的主要邏輯到這裏就結束了,咱們能夠看到,一小段代碼就能夠實現一個簡單的爬蟲。通常主流網頁都針對防爬蟲作了一些處理,實操過程當中也許並不會這麼順利,咱們可能須要模仿瀏覽器的User-Agent,或者作訪問延時防止請求過於頻繁等等處理。
pipelines是 Scrapy 用來後續處理的管道,能夠同時存在多個,而且能夠自定義順序執行,一般用來作數據處理和數據保存。咱們須要在settings.py
文件中設置須要須要執行的管道和執行順序。
# 在 settings.py 加入下面的代碼
ITEM_PIPELINES = {
'ScrapySample.pipelines.ScrapySamplePipeline': 300,
}
複製代碼
在這裏我只使用了一個管道ScrapySamplePipeline
,用來將數據保存到數據庫當中,後面的數字300
是表示該管道的優先級,數字越小優先級越高。
因爲咱們要保存數據到數據庫,因此咱們須要先在本地搭建起數據庫服務,我這裏用的是MySQL
,若是沒有搭建的小夥伴能夠下個 MAMP 免費版本,安裝好傻瓜式操做一鍵啓動Apache
、MySQL
服務。固然,數據庫和表仍是要本身建的。
# 在 pipelines.py 中加入數據庫配置信息
config = {
'host': '127.0.0.1',
'port': 8081,
'user': 'root',
'password': 'root',
'db': 'xietao',
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor,
}
複製代碼
咱們能夠在__init__()
函數裏作一些初始化工做,好比說鏈接數據庫。
而後process_item()
函數是管道處理事件的函數,咱們要在這裏將數據保存入數據庫,我在這個函數裏寫了一些插入數據庫操做。
close_spider()
函數是爬蟲結束工做時候調用,咱們能夠在這裏關閉數據庫。
class ScrapySamplePipeline(object):
def __init__(self):
# 鏈接數據庫
self.db = sql.connect(**config)
self.cursor = self.db.cursor()
def process_item(self, item, spider):
# 先保存做者信息
sql = 'INSERT INTO author (name, birthday, address, detail) VALUES (%s, %s, %s, %s)'
self.cursor.execute(sql, (item['author']['name'], item['author']['birthday'], item['author']['address'], item['author']['description']))
# 獲取做者id
author_id = self.cursor.lastrowid
# 保存引述信息
sql = 'INSERT INTO spider (text, tags, author) VALUES (%s, %s, %s)'
self.cursor.execute(sql, (item['text'], ','.join(item['tags']), author_id))
self.db.commit()
# 即將結束爬蟲
def close_spider(self, spider):
self.db.close()
self.cursor.close()
print('close db')
複製代碼
若是不須要保存數據庫或者對數據處理的話,pipelines
這部分是能夠忽略的。這個時候在命令行切換到工程目錄下,輸入開始執行爬蟲命令:
$ scrapy crawl quotes
複製代碼
部分不保存到數據庫的小夥伴可使用下方命令,將爬取的數據以 Json 格式導出到該工程目錄下。
$ scrapy crawl quotes -o quotes.json
複製代碼
最後貼上數據庫數據成功錄入的截圖。
這是做者最開始學習 Python 的時候寫的,有一些不盡人意的地方後面會再調整,寫下本文用意是鞏固知識或是用於之後回顧,同時但願對一樣剛開始學習 Python 的讀者有所幫助。
最後再次貼上Demo ️。