আমি একটি একক স্কেরাপি প্রকল্পে বিভিন্ন মাকড়সার জন্য কীভাবে পৃথক পাইপলাইন ব্যবহার করতে পারি


85

আমার একটি স্কেরাপি প্রকল্প রয়েছে যার মধ্যে একাধিক মাকড়সা রয়েছে। কোন মাকড়সার জন্য কোন পাইপলাইন ব্যবহার করতে হবে তার কোনও সংজ্ঞা দিতে পারি? আমি যে পাইপলাইনগুলি সংজ্ঞায়িত করেছি তা প্রতিটি মাকড়সার জন্য প্রযোজ্য নয়।

ধন্যবাদ


4
আপনার খুব ভাল প্রশ্নের জন্য আপনাকে ধন্যবাদ। ভবিষ্যতের সমস্ত গুগলারের জন্য দয়া করে একটি উত্তর নির্বাচন করুন। মিস্ট্রিঙ্গারের দেওয়া উত্তরটি আমার পক্ষে খুব ভাল কাজ করেছে।
সিম্বিওটেক

উত্তর:


36

পাবলো হফম্যানের সমাধানের ভিত্তিতে আপনি process_itemপাইপলাইন অবজেক্টের পদ্ধতিতে নীচের সজ্জা ব্যবহার করতে পারেন যাতে এটি pipelineআপনার মাকড়সার বৈশিষ্ট্য পরীক্ষা করে কিনা তা কার্যকর করা উচিত। উদাহরণ স্বরূপ:

def check_spider_pipeline(process_item_method):

    @functools.wraps(process_item_method)
    def wrapper(self, item, spider):

        # message template for debugging
        msg = '%%s %s pipeline step' % (self.__class__.__name__,)

        # if class is in the spider's pipeline, then use the
        # process_item method normally.
        if self.__class__ in spider.pipeline:
            spider.log(msg % 'executing', level=log.DEBUG)
            return process_item_method(self, item, spider)

        # otherwise, just return the untouched item (skip this step in
        # the pipeline)
        else:
            spider.log(msg % 'skipping', level=log.DEBUG)
            return item

    return wrapper

এই সাজসজ্জার সঠিকভাবে কাজ করার জন্য, মাকড়সার অবশ্যই পাইপলাইন বস্তুগুলির একটি ধারক সহ একটি পাইপলাইন বৈশিষ্ট্য থাকতে হবে যা আপনি আইটেমটি প্রক্রিয়া করতে ব্যবহার করতে চান, উদাহরণস্বরূপ:

class MySpider(BaseSpider):

    pipeline = set([
        pipelines.Save,
        pipelines.Validate,
    ])

    def parse(self, response):
        # insert scrapy goodness here
        return item

এবং তারপরে একটি pipelines.pyফাইলে:

class Save(object):

    @check_spider_pipeline
    def process_item(self, item, spider):
        # do saving here
        return item

class Validate(object):

    @check_spider_pipeline
    def process_item(self, item, spider):
        # do validating here
        return item

সমস্ত পাইপলাইন অবজেক্টগুলি এখনও সেটিংগুলিতে ITEM_PIPELINES এ সংজ্ঞায়িত করা উচিত (সঠিক ক্রমে - পরিবর্তনটি খুব ভাল হবে যাতে অর্ডারটি স্পাইডারেও নির্দিষ্ট করা যায়)।


আমি পাইপলাইনগুলির মধ্যে আপনার স্যুইচিংয়ের পদ্ধতিটি বাস্তবায়নের চেষ্টা করছি, আমি যদিও নামেরর! পাইপলাইন সংজ্ঞায়িত করা হয় না। আপনি কি এই কোডটি নিজে পরীক্ষা করেছেন? তুমি কি আমাকে সাহায্য করতে পারো?
মেহডিক্স_

। @ মেহডিক্স_ হ্যাঁ, এটি আমার পক্ষে কাজ করে। আপনি কোথায় নেমরার পাবেন?
mstringer

ত্রুটি ঠিক scrapy crawl <spider name>কমান্ড পরে আসে । পাইপলাইনের জন্য চালানোর জন্য স্পাইডার ক্লাসের মধ্যে আমি যে নামগুলি রেখেছি তা অজগর সনাক্ত করতে পারে না। আপনার নজর দেওয়ার জন্য আমি আপনাকে আমার স্পাইডার.পি এবং পাইপলাইন.পি এর লিঙ্কগুলি দেব । ধন্যবাদ
mehdix_

4
বিবৃতির জন্য ধন্যবাদ. প্রথম কোড স্নিপেট কোথায় যায়? কোথাও spider.pyডান শেষে ?
মেহডিক্স_

4
আমি ইতিমধ্যে সংজ্ঞায়িত মাকড়সাগুলিতে কোনও পাইপলাইন সেট নেই এমনগুলিতে ব্যর্থ না হওয়ার শর্তটি সম্পাদনা করেছি, অন্যথায় না বলা না হলে এটি ডিফল্টরূপে সমস্ত পাইপলাইনগুলি সম্পাদন করে। if not hasattr(spider, 'pipeline') or self.__class__ in spider.pipeline:
নুর ওল্ফ

140

কেবলমাত্র প্রধান সেটিংস থেকে সমস্ত পাইপলাইনগুলি সরান এবং মাকড়সার ভিতরে এটি ব্যবহার করুন।

এটি মাকড়সা প্রতি ব্যবহারকারীকে পাইপলাইনটি সংজ্ঞায়িত করবে

class testSpider(InitSpider):
    name = 'test'
    custom_settings = {
        'ITEM_PIPELINES': {
            'app.MyPipeline': 400
        }
    }

4
যার জন্য ভাবছেন যে '400' কী? আমার মতো - ডক থেকে - "এই সেটিংয়ের ক্লাসগুলিতে আপনি যে পূর্ণসংখ্যার মান নির্ধারণ করেন সেগুলি তাদের ক্রমটি নির্ধারণ করে: আইটেমগুলি নিম্ন মানের থেকে উচ্চ মানের শ্রেণিতে যায় classes এই সংখ্যাগুলি 0-1000 পরিসরে সংজ্ঞায়িত করার প্রথাগত" - ডকস.সেসিপি.আর.এন.এন
স্লেস্ট

4
নিশ্চিত না কেন এটি গ্রহণযোগ্য উত্তর নয়, নিখুঁতভাবে কাজ করে, গৃহীত উত্তরের চেয়ে অনেক পরিষ্কার এবং সহজ। আমি ঠিক এটিই খুঁজছিলাম। এখনও থেরাপিতে কাজ করছেন 1.8
এরিক এফ

4
সর্বাধিক থেরাপি 1.6 পরীক্ষা করা হয়েছে। সেটিংস.পাইতে পাইপলাইন সেটিংস মুছে ফেলার দরকার নেই। সেটিংস.পি-তে মাকড়সার ওভাররাইড পাইপলাইন সেটিংসে কাস্টম_সেটিংস।
গ্রাহাম মনকম্যান

আমার দৃশ্যের জন্য পুরোপুরি কাজ করে!
কামিশেক

'অ্যাপ্লিকেশন। আমার পাইপলাইন' এর জন্য পাইপলাইন শ্রেণীর পুরো নামটি প্রতিস্থাপন করুন। উদাহরণস্বরূপ, project.piplines.MyPiplines যেখানে প্রকল্পটি প্রকল্পের নাম, পাইপলাইনগুলি হ'ল পাইপলাইন.পি ফাইল এবং মাই পাইপলাইন হ'ল পাইপলাইন শ্রেণি
নাভা বোগতি

14

এখানে দেওয়া অন্যান্য সমাধানের ভালো, কিন্তু আমি মনে করি তারা, ধীর হতে পারে, কারণ আমরা নেই না মাকড়সা প্রতি পাইপলাইন ব্যবহার করে, এর পরিবর্তে আমরা যাচাই করছি একটি পাইপলাইন প্রত্যেক সময় একটি আইটেম ফিরিয়ে দেওয়া হয় যদি উপস্থিত থাকে (এবং কিছু কিছু ক্ষেত্রে এই পৌঁছতে পারে মিলিয়ন)।

মাকড়সা প্রতি বৈশিষ্ট্য সম্পূর্ণরূপে অক্ষম (বা সক্ষম) করার একটি ভাল উপায় custom_settingএবং এর from_crawlerমতো সমস্ত এক্সটেনশনের জন্য:

পাইপলাইন.পি

from scrapy.exceptions import NotConfigured

class SomePipeline(object):
    def __init__(self):
        pass

    @classmethod
    def from_crawler(cls, crawler):
        if not crawler.settings.getbool('SOMEPIPELINE_ENABLED'):
            # if this isn't specified in settings, the pipeline will be completely disabled
            raise NotConfigured
        return cls()

    def process_item(self, item, spider):
        # change my item
        return item

সেটিংস.পি

ITEM_PIPELINES = {
   'myproject.pipelines.SomePipeline': 300,
}
SOMEPIPELINE_ENABLED = True # you could have the pipeline enabled by default

spider1.py

class Spider1(Spider):

    name = 'spider1'

    start_urls = ["http://example.com"]

    custom_settings = {
        'SOMEPIPELINE_ENABLED': False
    }

আপনি যাচাই করে দেখুন, আমরা নির্দিষ্ট করেছি custom_settingsযা নির্দিষ্ট করা জিনিসগুলিকে ওভাররাইড করবে settings.pyএবং আমরা SOMEPIPELINE_ENABLEDএই মাকড়সার জন্য অক্ষম করছি।

এখন আপনি যখন এই মাকড়সা চালাবেন তখন এমন কিছু পরীক্ষা করুন:

[scrapy] INFO: Enabled item pipelines: []

এখন থেরাপি সম্পূর্ণরূপে পাইপলাইনটিকে অক্ষম করেছে, পুরো দৌড়ের জন্য এটির অস্তিত্ব নিয়ে বিরক্ত করছে না। এটিও স্কোথেরির জন্য extensionsএবং middlewares


12

আপনি nameআপনার পাইপলাইনে মাকড়সার বৈশিষ্ট্যটি ব্যবহার করতে পারেন

class CustomPipeline(object)

    def process_item(self, item, spider)
         if spider.name == 'spider1':
             # do something
             return item
         return item

সমস্ত পাইপলাইনগুলি এইভাবে সংজ্ঞায়িত করা আপনি যা চান তা পূরণ করতে পারে।


11

আমি কমপক্ষে চারটি পদ্ধতির কথা ভাবতে পারি:

  1. মাকড়সা + পাইপলাইনগুলির সেট প্রতি পৃথক স্কেরাপি প্রকল্প ব্যবহার করুন (আপনার মাকড়শা বিভিন্ন প্রকল্পে যথেষ্ট পরিমাণে ওয়ারেন্ট থাকায় উপযুক্ত হতে পারে)
  2. স্কেরাপি সরঞ্জাম কমান্ড লাইনে, scrapy settingsআপনার মাকড়সার প্রতিটি অনুরোধের মধ্যে পাইপলাইন সেটিংটি পরিবর্তন করুন
  3. আপনার মাকড়সাগুলি তাদের নিজস্ব চিকিত্সা সরঞ্জাম কমান্ডগুলিতে বিচ্ছিন্ন করুন এবং default_settings['ITEM_PIPELINES']আপনার কমান্ড বর্গের যে পাইপলাইন তালিকার জন্য আপনি চান সেই আদেশটি সংজ্ঞায়িত করুন । এই উদাহরণের লাইন 6 দেখুন ।
  4. process_item()খালি পাইপলাইন ক্লাসে, কোন মাকড়সার বিরুদ্ধে চলছে তা পরীক্ষা করে দেখুন এবং যদি সেই মাকড়সার জন্য এটি উপেক্ষা করা উচিত হয় তবে কিছুই করবেন না। আপনাকে শুরু করতে মাকড়সা প্রতি সংস্থান ব্যবহার করে উদাহরণ দেখুন । (এটি কুৎসিত সমাধানের মতো বলে মনে হচ্ছে কারণ এটি মাকড়সা এবং আইটেম পাইপলাইনগুলি দৃ tight়ভাবে সংযুক্ত করে You আপনার সম্ভবত এটি ব্যবহার করা উচিত নয়))

আপনার প্রতিক্রিয়ার জন্য ধন্যবাদ. আমি পদ্ধতি 1 ব্যবহার করছিলাম তবে আমি মনে করি যে একটি প্রকল্প ভাল পরিষ্কার এবং কোডটি আমার পুনরায় ব্যবহার করতে দেয়। আপনি দয়া করে 3 পদ্ধতিতে আরও বিস্তারিত বলতে পারেন i আমি কীভাবে মাকড়সাগুলিকে তাদের নিজস্ব সরঞ্জাম কমান্ডগুলিতে বিচ্ছিন্ন করব?
CodeMonkeyB

অন্য উত্তরে পোস্ট করা লিঙ্ক অনুসারে, আপনি পাইপলাইনগুলি ওভাররাইড করতে পারবেন না তাই আমি অনুমান করি 3 নম্বর কাজ করবে না।
ড্যানিয়েল ব্যাং

তুমি কি আমাকে এখানে আবেদন করতে সাহায্য করতে পার? stackoverflow.com/questions/25353650/...
মার্কো Dinatsoli

4

আপনি ঠিক এইভাবে মাকড়সার ভিতরে আইটেম পাইপলাইন সেটিংস সেট করতে পারেন:

class CustomSpider(Spider):
    name = 'custom_spider'
    custom_settings = {
        'ITEM_PIPELINES': {
            '__main__.PagePipeline': 400,
            '__main__.ProductPipeline': 300,
        },
        'CONCURRENT_REQUESTS_PER_DOMAIN': 2
    }

আমি তখন লোডার / ফেরত আইটেমটিতে একটি মান যুক্ত করে একটি পাইপলাইন (বা এমনকি একাধিক পাইপলাইনও ব্যবহার করতে পারি) বিভক্ত করতে পারি যা মাকড়সার কোন অংশটি প্রেরণ করে আইটেমগুলি প্রেরণ করেছে। এইভাবে আমি কোনও কী-এরর ব্যতিক্রম পাব না এবং আমি জানি যে কোন আইটেমটি পাওয়া উচিত।

    ...
    def scrape_stuff(self, response):
        pageloader = PageLoader(
                PageItem(), response=response)

        pageloader.add_xpath('entire_page', '/html//text()')
        pageloader.add_value('item_type', 'page')
        yield pageloader.load_item()

        productloader = ProductLoader(
                ProductItem(), response=response)

        productloader.add_xpath('product_name', '//span[contains(text(), "Example")]')
        productloader.add_value('item_type', 'product')
        yield productloader.load_item()

class PagePipeline:
    def process_item(self, item, spider):
        if item['item_type'] == 'product':
            # do product stuff

        if item['item_type'] == 'page':
            # do page stuff

4
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। আরও নমনীয় এবং কম জটিল
বেন উইলসন

2

সর্বাধিক সহজ এবং কার্যকর সমাধান হ'ল প্রতিটি মাকড়সার মধ্যেই কাস্টম সেটিংস সেট করা।

custom_settings = {'ITEM_PIPELINES': {'project_name.pipelines.SecondPipeline': 300}}

এর পরে আপনার সেগুলি সেটিংস.পাই ফাইলে সেট করা দরকার

ITEM_PIPELINES = {
   'project_name.pipelines.FistPipeline': 300,
   'project_name.pipelines.SecondPipeline': 400
}

সেভাবে প্রতিটি মাকড়সাড়ু সম্পর্কিত পাইপলাইন ব্যবহার করবে।


4
2020 সালের হিসাবে, এটিই সমস্যার পরিষ্কার সমাধান।
hashes4merkle

1

সহজ তবে তবুও দরকারী সমাধান।

স্পাইডার কোড

    def parse(self, response):
        item = {}
        ... do parse stuff
        item['info'] = {'spider': 'Spider2'}

পাইপলাইন কোড

    def process_item(self, item, spider):
        if item['info']['spider'] == 'Spider1':
            logging.error('Spider1 pipeline works')
        elif item['info']['spider'] == 'Spider2':
            logging.error('Spider2 pipeline works')
        elif item['info']['spider'] == 'Spider3':
            logging.error('Spider3 pipeline works')

আশা করি এটি কারও জন্য কিছুটা সময় সাশ্রয় করবে!


0

আমি দুটি পাইপলাইন ব্যবহার করছি, একটি চিত্র ডাউনলোডের জন্য (মাইআইমেজপাইপলাইন) এবং দ্বিতীয়টি মংডব (মঙ্গো পাইপলাইন) -এ ডেটা সংরক্ষণের জন্য।

ধরুন আমাদের অনেক মাকড়সা রয়েছে (স্পাইডার 1, স্পাইডার 2, ...........), আমার উদাহরণে স্পাইডার 1 এবং স্পাইডার 5 মাই ইমেজেস পাইপলাইন ব্যবহার করতে পারে না

সেটিংস.পি

ITEM_PIPELINES = {'scrapycrawler.pipelines.MyImagesPipeline' : 1,'scrapycrawler.pipelines.MongoPipeline' : 2}
IMAGES_STORE = '/var/www/scrapycrawler/dowload'

এবং পাইপলাইনের সম্পূর্ণ কোড বেলুন

import scrapy
import string
import pymongo
from scrapy.pipelines.images import ImagesPipeline

class MyImagesPipeline(ImagesPipeline):
    def process_item(self, item, spider):
        if spider.name not in ['spider1', 'spider5']:
            return super(ImagesPipeline, self).process_item(item, spider)
        else:
           return item 

    def file_path(self, request, response=None, info=None):
        image_name = string.split(request.url, '/')[-1]
        dir1 = image_name[0]
        dir2 = image_name[1]
        return dir1 + '/' + dir2 + '/' +image_name

class MongoPipeline(object):

    collection_name = 'scrapy_items'
    collection_url='snapdeal_urls'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'scraping')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        #self.db[self.collection_name].insert(dict(item))
        collection_name=item.get( 'collection_name', self.collection_name )
        self.db[collection_name].insert(dict(item))
        data = {}
        data['base_id'] = item['base_id']
        self.db[self.collection_url].update({
            'base_id': item['base_id']
        }, {
            '$set': {
            'image_download': 1
            }
        }, upsert=False, multi=True)
        return item

0

আমরা পাইপলাইনে কিছু শর্ত এটি ব্যবহার করতে পারি

    # -*- coding: utf-8 -*-
from scrapy_app.items import x

class SaveItemPipeline(object):
    def process_item(self, item, spider):
        if isinstance(item, x,):
            item.save()
        return item
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.