Python 萌新 - 花10分鐘學爬蟲

Python 新手入門不少時候都會寫個爬蟲練手,本教程使用 Scrapy 框架,幫你簡單快速實現爬蟲,並將數據保存至數據庫。在機器學習中數據挖掘也是十分重要的,個人數據科學老師曾經說過,好算法不如好數據。mysql

介紹

Scrapy ,Python 開發的一個快速、高層次的屏幕抓取和 web 抓取框架,用於抓取 web 站點並從頁面中提取結構化的數據。文件結構清晰,即便是小白也可以快速上手,總之很是好用😂。git

XPath ,它是一種用來查找 XML 文檔中節點位置的語言。 XPath 基於 XML 的樹狀結構,有不一樣類型的節點,包括元素節點,屬性節點和文本節點,提供在數據結構樹中找尋節點的能力。github

MySQL 是一種關係數據庫管理系統,它的優點:它是免費的。做者是下載了 MAMP for Mac ,內嵌MySQLApacheweb

首先經過 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    # 爬蟲主要代碼在這裏 
複製代碼

簡單的爬蟲主要使用了spidersitemspipelines這三個文件:bash

  • spider :爬蟲的主要邏輯。
  • items :爬蟲的數據模型。
  • pipelines : 爬蟲獲取到的數據的加工工廠,能夠進行數據篩選或保存。

數據模型:items

items

先看看咱們要爬取的網站,這個是 Scrapy 官方 Demo 爬取數據用的網站,咱們先用這個來練手。

quotes

分析網頁的信息咱們能夠看到網頁主體是一個列表,列表每一行都包含可一句引用、做者名字、標籤等信息。做者名右邊點擊(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
    }
}
複製代碼

爬蟲:spider

Spider

既然是爬蟲,天然須要去爬取網頁,爬蟲部分的幾個要點:

  1. 引入你建立的數據模型
  2. 首先爬蟲類要繼承scrapy.Spider
  3. 設置爬蟲的名字name,啓動爬蟲時要用。
  4. 將你要爬取的網址放入start_requests(),做爲爬蟲的起點。
  5. 爬取的網頁信息成功後,在的請求響應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

pipelines是 Scrapy 用來後續處理的管道,能夠同時存在多個,而且能夠自定義順序執行,一般用來作數據處理和數據保存。咱們須要在settings.py文件中設置須要須要執行的管道和執行順序。

# 在 settings.py 加入下面的代碼
ITEM_PIPELINES = {
   'ScrapySample.pipelines.ScrapySamplePipeline': 300,
}
複製代碼

在這裏我只使用了一個管道ScrapySamplePipeline,用來將數據保存到數據庫當中,後面的數字300是表示該管道的優先級,數字越小優先級越高。

因爲咱們要保存數據到數據庫,因此咱們須要先在本地搭建起數據庫服務,我這裏用的是MySQL,若是沒有搭建的小夥伴能夠下個 MAMP 免費版本,安裝好傻瓜式操做一鍵啓動ApacheMySQL服務。固然,數據庫和表仍是要本身建的。

MAMP

# 在 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
複製代碼

最後貼上數據庫數據成功錄入的截圖。

Data

總結

這是做者最開始學習 Python 的時候寫的,有一些不盡人意的地方後面會再調整,寫下本文用意是鞏固知識或是用於之後回顧,同時但願對一樣剛開始學習 Python 的讀者有所幫助。

最後再次貼上Demo ️。

相關文章
相關標籤/搜索