爬蟲學習之基於Scrapy的網絡爬蟲

概述


在上一篇文章《爬蟲學習之一個簡單的網絡爬蟲》中咱們對爬蟲的概念有了一個初步的認識,而且經過Python的一些第三方庫很方便的提取了咱們想要的內容,可是一般面對工做看成複雜的需求,若是都按照那樣的方式來處理效率很是的低,這一般須要你本身去定義並實現不少很是基礎的爬蟲框架上的功能,或者須要組合不少Python第三方庫來作。不過不用擔憂,Python中有不少很是優秀的爬蟲框架,好比咱們接下來要學習到的Scrapy。Scrapy官方有很經典的入門文檔說明,這一篇僅僅是經過一個簡單的實例來了解Scrapy這個庫是如何來進行網絡內容提取的,更深刻的學習請閱讀Scrapy官方文檔mysql

創建目標


一樣在作任何事情以前都須要明確目標,那此次咱們的目標是爬取一些技術性的文章並存儲到數據庫中。這就須要有目標網址和數據庫結構,數據庫咱們選擇使用MySql,目標網站咱們找了一個叫腳本之家的內容站。咱們這裏首先準備好一張用於存儲文章的表結構:git

CREATE TABLE `articles` (
  `id` mediumint(8) AUTO_INCREMENT NOT NULL,
  `title` varchar(255) DEFAULT NULL,
  `content` longtext,
  `add_date` int(11) DEFAULT 0,
  `hits` int(11) DEFAULT '0',
  `origin` varchar(500) DEFAULT '',
  `tags` varchar(45) DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `add_date` (`add_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

分析目標結構

這裏咱們首先須要爬取得入口是「網絡編程」這個節點,主入口網址爲(http://www.jb51.net/list/index_1.htm) 打開這個網站咱們經過Chrome或者其餘瀏覽器的查看元素來分析當前頁面的HTML語義結構,以下圖所示:github

從圖中紅色框線的部分能夠看出,這裏是咱們須要在「網絡編程」這個節點下須要提取的全部文章的主分類入口,經過這些入口能夠進去到不一樣文章分類的列表中。因此根據初步結構分析,咱們得出本次爬蟲的爬取路線爲:web

從主入口進去 -> 提取當前入口中的全部分類 -> 經過分類入口進入到分類列表 -> 經過列表進入到文章頁sql

分類入口肯定了接下來看看咱們的分類列表,隨意點開一個分類入口,打開列表以下圖所示:數據庫

這裏我框出了兩個主要部分,第一個是文章的標題,第二個是分頁,文章對應的URL就是咱們接下來須要爬取文章內容的入口,這裏須要注意的是分頁的處理,經過分頁的最後一頁咱們能夠知道當前這類列表共有多少頁文章。結合以上分析咱們基本肯定了本次爬蟲的各個路線入口,接下來咱們就開始經過程序來實現本次的目標。編程

實現爬蟲


在實現爬蟲以前咱們經過一張圖來對Scrapy有個基本的認識,爲了保持本章內容的簡潔性,咱們這裏暫時不會討論Item Pipeline部分,Scrapy架構圖以下所示(圖片來自網絡):瀏覽器

從圖中能夠很清晰的看到Scrapy所包含的幾大塊,下面咱們經過代碼來演示咱們所用到的基礎功能部分。
主要依賴第三方庫:服務器

web.py web框架,這裏只用到了database部分,未來會用來進行內容展現
scrapy 爬蟲框架,這裏只用到了最基本的內容提取網絡

這裏還會用到一些xpath相關知識,請自行Google瞭解xpath語法

# -*- coding:utf-8 -*-
'''by sudo rm -rf  http://imchenkun.com'''
import scrapy
from scrapy.http import Request
import web
import time

db = web.database(dbn='mysql', host='127.0.0.1', db='imchenkun', user='root', pw='root')

# 容許的站點域
allow_domain = "jb51.net"

base_url = "http://www.jb51.net"

# 列表頁
list_url = "http://www.jb51.net/list/list_%d_%d.htm"

# 列表分頁
list_page = 1

# 文章頁
crawl_url = "http://www.jb51.net/article/%d.htm"


class JB51Spider(scrapy.Spider):
    name = "jb51"
    start_urls = [
        "http://www.jb51.net/list/index_1.htm"
    ]

    cate_list = []

    def parse(self, response):
        cate_id = response.selector.xpath('//div[@class="index_bor clearfix"]/div[@class="index_con"]/span/a/@href').re('(\\\\d+)')[::2]
        for id in cate_id:
            cate_url = list_url % (int(id), 1)
            yield Request(cate_url, callback=self.parse_page)

    def parse_page(self, response):
        _params = response.selector.xpath('//div[@class="dxypage clearfix"]/a[last()]/@href').re('(\\\\d+)')
        cate_id = int(_params[0]) # 分類編號
        count = int(_params[1]) # 總頁數

        article_urls = response.selector.xpath('//div[@class="artlist clearfix"]/dl/dt/a/@href').extract()
        # 處理第一頁
        for article_url in article_urls:
            yield Request(base_url + article_url, callback=self.parse_article)

        # 處理其餘頁
        for page in range(1, count):
            url = (list_url % (cate_id, page + 1))
            yield Request(url, callback=self.parse_list)

    def parse_list(self, response):
        """解析文章列表"""
        article_urls = response.selector.xpath('//div[@class="artlist clearfix"]/dl/dt/a/@href').extract()
        for article_url in article_urls:
            yield Request(base_url + article_url, callback=self.parse_article)

    def parse_article(self, response):
        """解析文章內容"""
        title = response.selector.xpath('//div[@class="title"]/h1/text()').extract()[0]
        content = response.selector.xpath('//div[@id="content"]').extract()[0]
        tags = ','.join(response.selector.xpath('//div[@class="tags mt10"]/a/text()').extract())
        
        results = db.query('select count(0) as total from articles where origin=$origin', vars = { 'origin': response.url })
        if results[0].total <= 0:
            db.insert('articles',
                      title=title,
                      origin=response.url,
                      content=content,
                      add_date=int(time.time()),
                      hits=0,
                      tags=tags
            )

安裝Scrapy後以上代碼經過如下命令執行:

scrapy runspider jb51_spider.py

本次運行後的效果在數據庫中能夠見以下圖所示:

Github地址

總結


本篇文章咱們主要了解了基本的Scrapy Spider部分,並且經過對目標網站的結構分析使用xpath進行內容的提取,以及分頁的處理。這裏咱們的目的是創建一種寫爬蟲的思路,而不在於怎麼使用工具來爬數據。首先肯定目標,而後分析目標,再借助現有工具進行內容提取,提取內容的過程當中會遇到各類問題,這個時候咱們再來逐個解決這些問題,直到咱們的爬蟲可以無障礙的運行。接下來我會使用Scrapy更多的功能將繼續探索Item的定義,Pipeline的實現以及如何使用代理。

特別申明:本文所提到的腳本之家網站只是拿來進行爬蟲的技術交流學習,讀者涉及到的全部侵權問題都與本人無關,也但願你們在學習實戰的過程當中不要大量的爬取內容對服務器形成負擔

本文首發在sudo rm -rf 採用署名(BY)-非商業性使用(NC)-禁止演繹(ND) 轉載請註明原做者

相關文章
相關標籤/搜索