sql >> Databáze >  >> NoSQL >> MongoDB

Scrapy a procházení webu pomocí Scrapy a MongoDB

Minule jsme implementovali základní webový škrabák, který stahoval nejnovější otázky ze StackOverflow a ukládal výsledky do MongoDB. V tomto článku rozšíříme náš škrabák tak, aby procházel stránkovací odkazy v dolní části každé stránky a seškrabával otázky (název otázky a adresu URL) z každé stránky.

Box zdarma: Klikněte sem a stáhněte si kostru projektu Python + MongoDB s úplným zdrojovým kódem, který vám ukáže, jak přistupovat k MongoDB z Pythonu.

Aktualizace:

  1. 09/06/2015 – Aktualizováno na nejnovější verzi Scrapy (v1.0.3) a PyMongo (v3.0.3) – na zdraví!

Než se pustíte do jakékoli úlohy scrapingu, prostudujte si zásady používání webu a respektujte soubor robots.txt. Dodržujte také etické postupy stírání tím, že nezahlcujete web četnými požadavky během krátké doby. Zacházejte s každým webem, který oškrábete, jako by byl váš vlastní.

Toto je spolupráce mezi lidmi z Real Python a Györgym - nadšencem Pythonu a vývojářem softwaru, který v současné době pracuje ve velké datové společnosti a zároveň hledá novou práci. Otázky mu můžete pokládat na twitteru - @kissgyorgy.


Začínáme

Existují dva možné způsoby, jak pokračovat od místa, kde jsme skončili.

Prvním je rozšíření našeho stávajícího Spidera extrahováním každého odkazu na další stránku z odpovědi v parse_item metoda s výrazem xpath a pouze yield Request objekt se zpětným voláním na stejnou položku parse_item metoda. Tímto způsobem scrapy automaticky vytvoří nový požadavek na odkaz, který určíme. Více informací o této metodě naleznete v dokumentaci Scrapy.

Druhou, mnohem jednodušší možností je použít jiný typ pavouka – CrawlSpider (odkaz). Je to rozšířená verze základního Spider , navržený přesně pro náš případ použití.



The CrawlSpider

Budeme používat stejný projekt Scrapy z minulého tutoriálu, takže pokud ho potřebujete, stáhněte si kód z úložiště.


Vytvořte Boilerplate

V adresáři „stack“ začněte vygenerováním pavoučího standardu z crawl šablona:

$ scrapy genspider stack_crawler stackoverflow.com -t crawl
Created spider 'stack_crawler' using template 'crawl' in module:
  stack.spiders.stack_crawler

Projekt Scrapy by nyní měl vypadat takto:

├── scrapy.cfg
└── stack
    ├── __init__.py
    ├── items.py
    ├── pipelines.py
    ├── settings.py
    └── spiders
        ├── __init__.py
        ├── stack_crawler.py
        └── stack_spider.py

A stack_crawler.py soubor by měl vypadat takto:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule

from stack.items import StackItem


class StackCrawlerSpider(CrawlSpider):
    name = 'stack_crawler'
    allowed_domains = ['stackoverflow.com']
    start_urls = ['http://www.stackoverflow.com/']

    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        i = StackItem()
        #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()
        #i['name'] = response.xpath('//div[@id="name"]').extract()
        #i['description'] = response.xpath('//div[@id="description"]').extract()
        return i

Potřebujeme jen provést několik aktualizací tohoto standardu…



Aktualizujte start_urls seznam

Nejprve přidejte první stránku otázek do start_urls seznam:

start_urls = [
    'http://stackoverflow.com/questions?pagesize=50&sort=newest'
]


Aktualizujte rules seznam

Dále musíme pavoukovi sdělit, kde může najít odkazy na další stránku přidáním regulárního výrazu do rules atribut:

rules = [
    Rule(LinkExtractor(allow=r'questions\?page=[0-9]&sort=newest'),
         callback='parse_item', follow=True)
]

Scrapy bude nyní automaticky požadovat nové stránky na základě těchto odkazů a předá odpověď parse_item metoda k extrakci otázek a názvů.

Pokud dáváte dobrý pozor, tento regulární výraz omezuje procházení na prvních 9 stránek, protože u této ukázky nechceme odstranit všechny 176 234 stran!



Aktualizujte parse_item metoda

Teď už jen musíme napsat, jak analyzovat stránky pomocí xpath, což jsme již udělali v minulém tutoriálu - takže to prostě zkopírujte:

def parse_item(self, response):
    questions = response.xpath('//div[@class="summary"]/h3')

    for question in questions:
        item = StackItem()
        item['url'] = question.xpath(
            'a[@class="question-hyperlink"]/@href').extract()[0]
        item['title'] = question.xpath(
            'a[@class="question-hyperlink"]/text()').extract()[0]
        yield item

To je pro pavouka vše, ale ne ještě s tím začněte.



Přidat zpoždění stahování

Musíme být ke StackOverflow (a na jakýkoli web v tomto ohledu hodní) tím, že nastavíme zpoždění stahování v settings.py :

DOWNLOAD_DELAY = 5

To říká Scrapy, aby mezi každým novým požadavkem počkalo alespoň 5 sekund. V podstatě se omezujete. Pokud to neuděláte, StackOverflow vás omezí; a pokud budete pokračovat v odstraňování stránek bez zavedení omezení rychlosti, vaše IP adresa může být zakázána. Buďte tedy hodní – Zacházejte s každým webem, který seškrábnete, jako by byl váš vlastní.

Nyní zbývá udělat jen jednu věc – uložit data.




MongoDB

Minule jsme stáhli pouze 50 otázek, ale protože tentokrát sbíráme mnohem více dat, chceme se vyhnout přidávání duplicitních otázek do databáze. Můžeme to udělat pomocí MongoDB upsert, což znamená, že aktualizujeme název otázky, pokud je již v databázi, a vložíme jinak.

Upravte MongoDBPipeline jsme definovali dříve:

class MongoDBPipeline(object):

    def __init__(self):
        connection = pymongo.MongoClient(
            settings['MONGODB_SERVER'],
            settings['MONGODB_PORT']
        )
        db = connection[settings['MONGODB_DB']]
        self.collection = db[settings['MONGODB_COLLECTION']]

    def process_item(self, item, spider):
        for data in item:
            if not data:
                raise DropItem("Missing data!")
        self.collection.update({'url': item['url']}, dict(item), upsert=True)
        log.msg("Question added to MongoDB database!",
                level=log.DEBUG, spider=spider)
        return item

Pro jednoduchost jsme dotaz neoptimalizovali a nezabývali se indexy, protože se nejedná o produkční prostředí.



Test

Spusťte pavouka!

$ scrapy crawl stack_crawler

Nyní se pohodlně usaďte a sledujte, jak se vaše databáze plní daty!

$ mongo
MongoDB shell version: 3.0.4
> use stackoverflow
switched to db stackoverflow
> db.questions.count()
447
>


Závěr

Celý zdrojový kód si můžete stáhnout z úložiště Github. Komentář níže s dotazy. Na zdraví!

Box zdarma: Klikněte sem a stáhněte si kostru projektu Python + MongoDB s úplným zdrojovým kódem, který vám ukáže, jak přistupovat k MongoDB z Pythonu.

Hledáte další web scraping? Nezapomeňte se podívat na kurzy Real Python. Hledáte najmout profesionálního škrabka na web? Podívejte se na GoScrape.



  1. MurmurHash - co to je?

  2. Mongodb:Nepodařilo se připojit k serveru při prvním připojení

  3. Automatizujte kontrolu stavu databáze

  4. Jak provést vnořené vyhledávání $lookup v MongoDB?