Scrapy学習(三)豆弁図書情報を這い出す


前言
  • Scrapyラーニング(一)インストール
  • Scrapy学習(二)入門
  • 前の2編の基礎があれば、インターネット上で私たちの興味のある情報を抽出することができます.しばらくはログインのシミュレーションを学んでいないので、豆弁のようにログインする必要のないサイトの内容をつかんでおきます.私の開発環境はWin 7+PyChram+Python 3です.5+MongoDB爬虫類のターゲットは豆弁の日本文学のラベルの下のすべての書籍の基本情報です
    プロジェクトの作成
    scrapy startproject douban
    次にdoubanディレクトリに移動
    scrapy genspider book book.douban.com
    対応するBookSpiderテンプレートをspiderディレクトリの下で生成
    Itemの作成
    itemsでpyで必要なデータモデルを作成する
    class BookItem(scrapy.Item):
        book_name = scrapy.Field()
        book_star = scrapy.Field()
        book_pl = scrapy.Field()
        book_author = scrapy.Field()
        book_publish = scrapy.Field()
        book_date = scrapy.Field()
        book_price = scrapy.Field()

    Spiderの作成
    豆弁の日本文学のラベルを訪問し、urlの値をstart_urlsに書いた.それからChromeの助けのもとで、1冊の図書がul#subject-list > li.subject-itemであることを見ることができます
    class BookSpider(scrapy.Spider):
        ...
        def parse(self, response):
            sel = Selector(response)
            book_list = sel.css('#subject_list > ul > li')
            for book in book_list:
                item = BookItem()
                item['book_name'] = book.xpath('div[@class="info"]/h2/a/text()').extract()[0].strip()
                item['book_star'] = book.xpath("div[@class='info']/div[2]/span[@class='rating_nums']/text()").extract()[
                    0].strip()
                item['book_pl'] = book.xpath("div[@class='info']/div[2]/span[@class='pl']/text()").extract()[0].strip()
                pub = book.xpath('div[@class="info"]/div[@class="pub"]/text()').extract()[0].strip().split('/')
                item['book_price'] = pub.pop()
                item['book_date'] = pub.pop()
                item['book_publish'] = pub.pop()
                item['book_author'] = '/'.join(pub)
                yield item

    コードに問題があるかどうかをテストします
    scrapy crawl book -o items.json
    奇妙な発見だitemsjson内にはデータがないので、コンソールのDEBUG情報を後から見ます
    2017-02-04 16:15:38 [scrapy.core.engine] INFO: Spider opened2017-02-04 16:15:38 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2017-02-04 16:15:38 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:60232017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403) 2017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403)
    ページを這い出すときのステータスコードは403です.これは、サーバが爬虫類プログラムを判断し、アクセスを拒否したためです.settingsでUSER_AGENTの値を設定し、ブラウザアクセスページに偽装することができます.
    USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
    もう一度やってみるとitems.jsonは価値がある.しかし、最初のページのデータしかありません.すべてのデータを取得するには、現在のページを登った後、次のページのurlを自動的に取得し、すべてのデータをスクロールする必要があります.spiderを改造しました
        ...
        def parse(self, response):
            sel = Selector(response)
            book_list = sel.css('#subject_list > ul > li')
            for book in book_list:
                item = BookItem()
                try:
                    item['book_name'] = book.xpath('div[@class="info"]/h2/a/text()').extract()[0].strip()
                    item['book_star'] = book.xpath("div[@class='info']/div[2]/span[@class='rating_nums']/text()").extract()[0].strip()
                    item['book_pl'] = book.xpath("div[@class='info']/div[2]/span[@class='pl']/text()").extract()[0].strip()
                    pub = book.xpath('div[@class="info"]/div[@class="pub"]/text()').extract()[0].strip().split('/')
                    item['book_price'] = pub.pop()
                    item['book_date'] = pub.pop()
                    item['book_publish'] = pub.pop()
                    item['book_author'] = '/'.join(pub)
                    yield item
                except:
                    pass
            nextPage = sel.xpath('//div[@id="subject_list"]/div[@class="paginator"]/span[@class="next"]/a/@href').extract()[0].strip()
            if nextPage:
                next_url = 'https://book.douban.com'+nextPage
                yield scrapy.http.Request(next_url,callback=self.parse)

    そのうちscrapy.http.Requestはparse関数をコールバックしtry...catchは豆弁図書がフォーマットが一致していないからです.問題のあるデータに出会ったら、捨てて使いません.
    反爬虫類を突き破る
    一般的に、爬虫類の速度が速すぎると.サイトがアクセスを拒否するため、settingsで爬虫類の間隔を設定し、COOKIESをオフにする必要があります.
    DOWNLOAD_DELAY = 2COOKIES_ENABLED = False
    あるいは、ウェブサイトのマスクを回避するために、異なるブラウザUAまたはIPアドレスを設定することができ、次にUAを変更することを例に挙げることができる.middlewaresでpy,UAをランダムに置換するミドルウェアを作成し,各requestはmiddlewareを通過する.このうちprocess_requestNoneを返し、Scrapyは他のmiddlewareに処理を続行します.
    class RandomUserAgent(object):
        def __init__(self,agents):
            self.agents = agents
        @classmethod
        def from_crawler(cls,crawler):
            return cls(crawler.settings.getlist('USER_AGENTS'))
        def process_request(self,request,spider):
            request.headers.setdefault('User-Agent',random.choice(self.agents))

    続く道settingsに設けられている
    DOWNLOADER_MIDDLEWARES = {
    'douban.middlewares.RandomUserAgent': 1,
    }
    ...
    USER_AGENTS = [
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
        ...
    ]

    プログラムを再実行すると、明らかに速度が速くなった.
    MongoDBに保存
    次に、データをデータベースに保存して永続化処理を行います(ここではMongoDBを例に挙げて、他のデータベースに保存します).この処理はpipelinesに記載されている.その前に、接続データベースのドライバをインストールします.
    pip install pymongo settingsに構成を書きます
    # MONGODB configure
    MONGODB_SERVER = 'localhost'
    MONGODB_PORT = 27017
    MONGODB_DB = 'douban'
    MONGODB_COLLECTION = "book"
    class MongoDBPipeline(object):
        def __init__(self):
            connection = MongoClient(
                host=settings['MONGODB_SERVER'],
                port=settings['MONGODB_PORT']
            )
            db = connection[settings['MONGODB_DB']]
            self.collection = db[settings['MONGODB_COLLECTION']]
    
        def process_item(self, item, spider):
            self.collection.insert(dict(item))
            log.msg("Book  added to MongoDB database!",
                    level=log.DEBUG, spider=spider)
            return item

    その他
    プロジェクト実行時にコンソールから出力されたDEBUG情報をログファイルに保存します.settingsに設定するだけです
    LOG_FILE = "logs/book.log"
    項目コード住所:豆弁図書爬虫類