نصب و استفاده از خزنده Scrapy

با سلام و درود، چند وقتی هست که درگیر پروژه ای هست که در اون باید از خزنده (crawler) استفاده کنم. پروژه با Django نوشته شده و در نتیجه باید از خزنده ای که با پایتون نوشته شده استفاده می کردم ( آموزش Scrapy در پایتون ).

خزنده یا Crawler برای پایتون چند نمونه خیلی خوب وجود داره که من اسم دو تا از بهتریناشون رو پایین آوردم و لینک دسترسی بهشون :

۱- اولی scrapy هست که تو این مقاله بهش پرداخته شده و اینجا و اینجا می توانید بیشتر در مودرش مطالعه کنید.

۲- دومی pyspider نام داره، میتویند اینجا و اینجا در موردش بیشتر مطالعه کنید.

من همون طور که گفتم تو این پروژه از scrapy استفاده کردم. به صورت آماری اگه نگاه کنیم «اسکرپی» ۳ برابر «پی وای اسپایدر» در گیت هاب ستاره داره :)) مقایسه اصولی و کاملترش رو به خودتون میسپارم.

اسکرپی ادعا داره که خزنده وب سریع و سطح بالایی هست. نیازمندی هاش پایتون ۲۷ یا ۳.۵+ هست و روی سیستم عامل های لینوکس، ویندوز، مک و BSD کار می کنه.

برای نصبش کافیه از دستور زیر استفاده کنید.

pip install scrapy

پس از نصب برای ساخت یه پروژه با scrapy کافیست دستور زیر رو استفاده کنید. toturial اسم پروژه شماست.

scrapy startproject tutorial

ساختار پروژه به شکل زیر خواهد بود:

داخل فولدر spiders فایلی با نام sadegh-khan-spider.py می سازیم.

محتوای فایل به شکل زیر خواهد بود :

# -*- coding: utf-8 -*-
# How to run sadegh : scrapy crawl amazon -o items.json
import scrapy
from toturial.items import SadeghKhanItem


class SadeghKhanSpider(scrapy.Spider):
    name = 'sadeghKhan'
    allowed_domains = ['sadegh-khan.ir']
    start_urls = [
        'https://sadegh-khan.ir/%d8%a2%d9%85%d9%88%d8%b2%d8%b4-%d9%86%d8%b5%d8%a8-google-earth-%d8%b1%d9%88%db%8c-%d9%84%db%8c%d9%86%d9%88%da%a9%d8%b3-%d8%a7%d9%88%d8%a8%d9%88%d9%86%d8%aa%d9%88/',
        ]

    def parse(self, response):
        items = SadeghKhanItem()
        title = response.css('h1.w-blog-post-title::text').extract()
        datetime = response.css(
            'div.l-section-h time.w-blog-post-meta-date::text').extract()
        category = response.css(
            'span.w-blog-post-meta-category a').extract()
        items['post_title'] = ''.join(title).strip()
        items['post_date'] = ''.join(datetime).strip()
        items['post_category'] = ','.join(
            map(lambda x: x.strip(), category)
            ).strip()
        yield items

سعی می کنم جاهایی از کد کع نیاز به توضیح داره رو توضیح بدم.

اول از همه خط زیر :

from toturial.items import SadeghKhanItem

toturial اسم پروژه ما بود و item نیز به هنگام ساخت پروژه ساخته شده است. فایل items.py . تو این فایل در حقیقت اون آیتم هایی که ما قصد داریم توسط خزنده استخراج کنیم رو مشخص می کنیم. محتوای داخل فایل items.py به ضرح زیر است:

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

import scrapy


class SadeghKhanItem(scrapy.Item):
    # define the fields for your item here like:
    post_title = scrapy.Field()
    post_date = scrapy.Field()
    post_category = scrapy.Field()

ما قصد داریم برای هر صفحه از مقالات یا پست های وب سایت sadegh-khan.ir سه فیلد عنوان، تاریخ و دسته بندی را استخراج کنیم.

و اما خط :

class SadeghKhanSpider(scrapy.Spider):

همون طور که مشخص هست یه کلاس داریم که از scrapy.Spider ارث بری کرده است.

name نام اسپایدر ما را مشخص می کند که بعدا با این نام بهش دسترسی پیدا می کنیم و اسپایدر را فراخوانی می کنیم.

تو این مثال ما نام اسپایدرمان را sadeghKhan گذاشتیم.

می رسیم به allowed_domains و start_urls ، از عنوانشون مشخصه که چه کاربردی دارند. برای این مثال ما allowed_domains را به بلاگ sadegh-khan.ir محدود کردیم و همچنین start_urls را یکی از پست های بلاگ با عنوان «آموزش نصب Google Earth روی لینوکس اوبونتو» در نظر گرفتیم.

اما داخل فانکشن parse ، ما باید مواردی که میخوایم از بلاگ استخراج بشود را به item هایی که قبلا تعریف کردیم لینک کنیم.

قدم اول بدست آوردن سه آیتم عنوان، تاریخ و دسته بندی از بلاگ هست که اگر یه مقدار css و html بلد باشید و با استفاده از developer panel مرور گرتان به راحتی بدست می آوریدشان 🙂 یه روش ساده تر استفاده از اکستنشنی با نام selector lib از اکستنشن های گوگل کروم می باشد.

حال کافیست اسپایدرمان رو اجرا کنیم ، برای این کار کافیست دستور زیر را اجرا کنیم، با دستور زیر موارد استخراج شده در فایلی با نام sadegh-khan-output.json و در پوشه اصلی پروژه ذخیره خواهد شد:

scrapy crawl sadeghKhan -o sadegh-khan-output.json

خب یه مثال از استخراج لینک عکس های یک محصول آمازون لا استفاده از خزمده scrapy :

# -*- coding: utf-8 -*-                                                         
import js2xml                                                                   
import scrapy                                                                   

class ExampleSpider(scrapy.Spider):                                             
    name = 'example'                                                            
    allowed_domains = ['amazon.com']                                            
    start_urls = ['https://www.amazon.com/dp/B01N068GIX?psc=1/']                

    def parse(self, response):                                                  
        item = dict()
        js = response.xpath("//script[contains(text(), 'register(\"ImageBlockATF\"')]/text()").extract_first()
        xml = js2xml.parse(js)                                                  
        selector = scrapy.Selector(root=xml)                                   
        item['image_urls'] = selector.xpath('//property[@name="colorImages"]//property[@name="hiRes"]/string/text()').extract()
        yield item

همانطور که می بینید از کتابخانه js2xml برای تبدیل سورس کد JavaScript به XML استفاده شده است(می تونید اینجا بیشتر در موردش مطالعه کنید).

در ادامه حتما یه مطلبی در مورد استفاده از scrapy داخل یه اسکریپت رو آموزش خواهم داد (داخل پروژه django از scrapy استفاده کنیم)