Python Scrapy 學習----自動爬取網頁

使用scrapy框架寫爬蟲時一般會在start_urls中指定我們需要爬蟲去抓取的網頁的url,但是如何讓我們的爬蟲像搜索引擎中使用的爬蟲一樣具備自動多網頁爬取的功能呢?本文通過自動抓取個人csdn博客的所有文章標題、閱讀人數、創建時間來進行一個簡單的說明。文中使用了兩種不同的方法來實現。
首先我們來分析cdsn中博客中文章的url,如圖所示可以發現不同的文章頁面的url只有url末尾對應的一串數字編號不同,而且在每篇文章的下面會有連接指向上一篇或者下一篇文章。因此我們可以提取這個鏈接實現網頁的自動抓取。
這裏寫圖片描述

在scrapy框架上編寫爬蟲整體流程和上一篇文章中的流程一樣這裏不再重複直接貼代碼。
items.py

import scrapy


class CsdnItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    title=scrapy.Field()
    time=scrapy.Field()
    readtimes=scrapy.Field()
    article_url=scrapy.Field()
    pass

pipelines.py

import codecs
import json
from scrapy import signals

class CsdnPipeline(object):
    def __init__(self):
    self.file=codecs.open('data.json','w',encoding='utf-8')

    def process_item(self, item, spider):
    line=json.dumps(dict(item))+'\n'
    self.file.write(line.decode("unicode_escape"))
        return item

    def spider_closed(self,spider):
    self.file.close()

settings.py

# -*- coding: utf-8 -*-

# Scrapy settings for csdn project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#


BOT_NAME = 'csdn'

SPIDER_MODULES = ['csdn.spiders']
NEWSPIDER_MODULE = 'csdn.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'csdn (+http://www.yourdomain.com)'
USER_AGENT = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0'
ITEM_PIPELINES = {
    'csdn.pipelines.CsdnPipeline':300,
}
DOWNLOAD_DELAY = 2
COOKIES_ENABLED=False

然後是最關鍵的爬蟲部分,第一種方法我們還是使用普通的Spider來完成,在start_urls中放置要抓取的第一篇文章的地址,在抓取完這篇文章的基本信息後放入定義好的item中,然後提取出下一篇文章的連接地址,結合python中yield,通過Request函數請求這個鏈接並在回調函數中處理請求返回頁面的內容。具體代碼如下:
spider1.py

#-*- coding:utf-8 -*-

from scrapy.spider import Spider
from scrapy.http import Request
from scrapy.selector import Selector
from csdn.items import CsdnItem

class csdnSpider(Spider):
    name="csdn"
    download_delay=1
    allowed_domains=["blog.csdn.net"]
    start_urls=[
        "http://blog.csdn.net/u012286517/article/details/49556723"
    ]

    def parse(self,response):
        sel=Selector(response)
        item=CsdnItem()
        title=sel.xpath('//div[@id="article_details"]/div/h1/span/a/text()').extract()
        article_url = str(response.url)
        time=sel.xpath('//div[@id="article_details"]/div[2]/div/span[@class="link_postdate"]/text()').extract()
        readtimes=sel.xpath('//div[@id="article_details"]/div[2]/div/span[@class="link_view"]/text()').extract()
        item['title']=[n.encode('utf-8').replace("\r\n","").strip() for n in title]
        item['time']=[n.encode('utf-8') for n in time]
        item['readtimes']=[n.encode('utf-8') for n in readtimes]
        yield item
        #get next url   
        urls=sel.xpath('//li[@class="next_article"]/a/@href').extract()
        for url in urls:
            print url
            url="http://blog.csdn.net"+url
            print url
            yield Request(url,callback=self.parse)

第二種方法我們用scrapy框架中提供的CrawlSpider,它是Spider的派生類,普通的spider只會爬取start_urls中定義的路徑網頁,但CrawlSpider定義了一些規則(rule)來提供跟進link的方便的機制。 也許該spider並不是完全適合您的特定網站或項目,但其對很多情況都使用。 因此您可以以其爲起點,根據需求修改部分方法。當然您也可以實現自己的spider。

除了從Spider繼承過來的(您必須提供的)屬性外,其提供了一個新的屬性:
rules:
一個包含一個(或多個) Rule 對象的集合(list)。 每個 Rule 對爬取網站的動作定義了特定表現。 Rule對象在下邊會介紹。 如果多個rule匹配了相同的鏈接,則根據他們在本屬性中被定義的順序,第一個會被使用。
該spider也提供了一個可複寫(overrideable)的方法:
parse_start_url(response)
當start_url的請求返回時,該方法被調用。 該方法分析最初的返回值並必須返回一個 Item 對象或者 一個 Request 對象或者 一個可迭代的包含二者對象。

具體實現代碼如下:

#-*- coding:utf-8 -*-

from scrapy.contrib.spiders import CrawlSpider, Rule  
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor  
from scrapy.selector import Selector 
from csdn.items import CsdnItem

class csdnSpider2(CrawlSpider):
    name="csdn2"
    download_delay=1
    allowed_domains=["blog.csdn.net"]
    start_urls=[
        "http://blog.csdn.net/u012286517/article/details/49556723"
    ]
    rules = [  
        Rule(SgmlLinkExtractor(allow=('/u012286517/article/details'),  
                              restrict_xpaths=('//li[@class="next_article"]')),  
             callback='parse_item',  
             follow=True)  
    ]  
    def parse_item(self, response):
        sel=Selector(response)
        item=CsdnItem()
        title=sel.xpath('//div[@id="article_details"]/div/h1/span/a/text()').extract()
        article_url = str(response.url)
        time=sel.xpath('//div[@id="article_details"]/div[2]/div/span[@class="link_postdate"]/text()').extract()
        readtimes=sel.xpath('//div[@id="article_details"]/div[2]/div/span[@class="link_view"]/text()').extract()
        item['title']=[n.encode('utf-8').replace("\r\n","").strip() for n in title]
        item['time']=[n.encode('utf-8') for n in time]
        item['readtimes']=[n.encode('utf-8') for n in readtimes]
        yield item

在rules中我們定義瞭如何從爬取到的頁面提取鏈接,在這例子中即鏈接滿足‘/u012286517/article/details’正則表達式。同時通過restrict_xpath來限定只從頁面特定的部分來抽取接下來將要爬取的鏈接。
與運行代碼我們得到如下結果,其中紅線部分代表抓取的一篇文章:
這裏寫圖片描述
我們再看一下爬取的信息部分:其中我們可以清楚的看到請求次數以及響應次數爲20,與博客中的文章數目一致。
這裏寫圖片描述

下圖是爬取返回的信息以及csdn中文章列表對比:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章