MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Pengikisan dan Perayapan Web dengan Scrapy dan MongoDB

Terakhir kali kami menerapkan scraper web dasar yang mengunduh pertanyaan terbaru dari StackOverflow dan menyimpan hasilnya di MongoDB. Dalam artikel ini kami akan memperluas scraper kami sehingga merayapi link pagination di bagian bawah setiap halaman dan menggores pertanyaan (judul pertanyaan dan URL) dari setiap halaman.

Bonus Gratis: Klik di sini untuk mengunduh kerangka proyek Python + MongoDB dengan kode sumber lengkap yang menunjukkan cara mengakses MongoDB dari Python.

Pembaruan:

  1. 06/09/2015 - Diperbarui ke versi terbaru Scrapy (v1.0.3) dan PyMongo (v3.0.3) - semangat!

Sebelum Anda memulai pekerjaan pengikisan, tinjau kebijakan persyaratan penggunaan situs dan hormati file robots.txt. Selain itu, patuhi praktik pengikisan etis dengan tidak membanjiri situs dengan banyak permintaan dalam rentang waktu yang singkat. Perlakukan situs apa pun yang Anda kikis seolah-olah itu milik Anda sendiri.

Ini adalah bagian kolaborasi antara orang-orang di Real Python dan György - penggemar Python dan pengembang perangkat lunak, saat ini bekerja di perusahaan data besar dan mencari pekerjaan baru pada saat yang sama. Anda dapat mengajukan pertanyaan kepadanya di twitter - @kissgyorgy.


Memulai

Ada dua cara yang mungkin untuk melanjutkan dari bagian terakhir yang kita tinggalkan.

Yang pertama adalah memperluas Spider yang ada dengan mengekstrak setiap tautan halaman berikutnya dari respons di parse_item metode dengan ekspresi xpath dan hanya yield sebuah Request objek dengan panggilan balik ke parse_item yang sama metode. Dengan cara ini scrapy secara otomatis akan membuat request baru ke link yang kita tentukan. Anda dapat menemukan informasi lebih lanjut tentang metode ini di dokumentasi Scrapy.

Opsi lain yang jauh lebih sederhana adalah menggunakan jenis laba-laba yang berbeda - CrawlSpider (tautan). Ini adalah versi lanjutan dari Spider dasar , dirancang persis untuk kasus penggunaan kami.



Spider Perayapan

Kami akan menggunakan proyek Scrapy yang sama dari tutorial terakhir, jadi ambil kode dari repo jika Anda membutuhkannya.


Buat Boilerplate

Di dalam direktori “stack”, mulailah dengan membuat spider boilerplate dari crawl templat:

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

Proyek Scrapy sekarang akan terlihat seperti ini:

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

Dan stack_crawler.py file akan terlihat seperti ini:

# -*- 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

Kami hanya perlu melakukan beberapa pembaruan pada boilerplate ini…



Perbarui start_urls daftar

Pertama, tambahkan halaman pertama pertanyaan ke start_urls daftar:

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


Perbarui rules daftar

Selanjutnya, kita perlu memberi tahu laba-laba di mana ia dapat menemukan tautan halaman berikutnya dengan menambahkan ekspresi reguler ke rules atribut:

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

Scrapy sekarang akan secara otomatis meminta halaman baru berdasarkan tautan tersebut dan meneruskan respons ke parse_item metode untuk mengekstrak pertanyaan dan judul.

Jika Anda memperhatikan dengan seksama, ekspresi reguler ini membatasi perayapan ke 9 halaman pertama karena untuk demo ini kami tidak ingin mengikis semua 176.234 halaman!



Perbarui parse_item metode

Sekarang kita hanya perlu menulis cara mengurai halaman dengan xpath, yang sudah kita lakukan di tutorial terakhir - jadi salin saja:

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

Itu untuk laba-laba, tetapi jangan mulai dulu.



Tambahkan Penundaan Unduhan

Kita harus bersikap baik terhadap StackOverflow (dan situs apa pun, dalam hal ini) dengan menyetel penundaan unduhan di settings.py :

DOWNLOAD_DELAY = 5

Ini memberitahu Scrapy untuk menunggu setidaknya 5 detik antara setiap permintaan baru yang dibuatnya. Anda pada dasarnya menilai membatasi diri sendiri. Jika Anda tidak melakukan ini, StackOverflow akan membatasi Anda; dan jika Anda terus mengikis situs tanpa menerapkan batas tarif, alamat IP Anda dapat diblokir. Jadi, bersikaplah baik - Perlakukan situs apa pun yang Anda kikis seolah-olah itu milik Anda sendiri.

Sekarang hanya ada satu hal yang harus dilakukan - menyimpan data.




MongoDB

Terakhir kali kami hanya mengunduh 50 pertanyaan, tetapi karena kami mengambil lebih banyak data kali ini, kami ingin menghindari penambahan pertanyaan duplikat ke database. Kita dapat melakukannya dengan menggunakan upsert MongoDB, yang berarti kita memperbarui judul pertanyaan jika sudah ada di database dan menyisipkan sebaliknya.

Ubah MongoDBPipeline kita definisikan sebelumnya:

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

Untuk mempermudah, kami tidak mengoptimalkan kueri dan tidak menangani indeks karena ini bukan lingkungan produksi.



Uji

Mulai laba-laba!

$ scrapy crawl stack_crawler

Sekarang duduk dan saksikan database Anda terisi dengan data!

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


Kesimpulan

Anda dapat mengunduh seluruh kode sumber dari repositori Github. Komentar di bawah dengan pertanyaan. Semangat!

Bonus Gratis: Klik di sini untuk mengunduh kerangka proyek Python + MongoDB dengan kode sumber lengkap yang menunjukkan cara mengakses MongoDB dari Python.

Mencari lebih banyak web scraping? Pastikan untuk memeriksa kursus Python Nyata. Ingin menyewa scraper web profesional? Lihat GoScrape.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Cara Menjatuhkan Database di MongoDB dari Command Line

  2. Bagaimana cara menambah nilai Angka di Mongoose?

  3. Memasang di Mongo DB menggunakan driver C # resmi

  4. Layanan MongoDB tidak berjalan di Fedora

  5. Pengindeksan luwak dalam kode produksi