আমার একটি স্কেরাপি প্রকল্প রয়েছে যার মধ্যে একাধিক মাকড়সা রয়েছে। কোন মাকড়সার জন্য কোন পাইপলাইন ব্যবহার করতে হবে তার কোনও সংজ্ঞা দিতে পারি? আমি যে পাইপলাইনগুলি সংজ্ঞায়িত করেছি তা প্রতিটি মাকড়সার জন্য প্রযোজ্য নয়।
ধন্যবাদ
আমার একটি স্কেরাপি প্রকল্প রয়েছে যার মধ্যে একাধিক মাকড়সা রয়েছে। কোন মাকড়সার জন্য কোন পাইপলাইন ব্যবহার করতে হবে তার কোনও সংজ্ঞা দিতে পারি? আমি যে পাইপলাইনগুলি সংজ্ঞায়িত করেছি তা প্রতিটি মাকড়সার জন্য প্রযোজ্য নয়।
ধন্যবাদ
উত্তর:
পাবলো হফম্যানের সমাধানের ভিত্তিতে আপনি 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 এ সংজ্ঞায়িত করা উচিত (সঠিক ক্রমে - পরিবর্তনটি খুব ভাল হবে যাতে অর্ডারটি স্পাইডারেও নির্দিষ্ট করা যায়)।
scrapy crawl <spider name>
কমান্ড পরে আসে । পাইপলাইনের জন্য চালানোর জন্য স্পাইডার ক্লাসের মধ্যে আমি যে নামগুলি রেখেছি তা অজগর সনাক্ত করতে পারে না। আপনার নজর দেওয়ার জন্য আমি আপনাকে আমার স্পাইডার.পি এবং পাইপলাইন.পি এর লিঙ্কগুলি দেব । ধন্যবাদ
spider.py
ডান শেষে ?
if not hasattr(spider, 'pipeline') or self.__class__ in spider.pipeline:
কেবলমাত্র প্রধান সেটিংস থেকে সমস্ত পাইপলাইনগুলি সরান এবং মাকড়সার ভিতরে এটি ব্যবহার করুন।
এটি মাকড়সা প্রতি ব্যবহারকারীকে পাইপলাইনটি সংজ্ঞায়িত করবে
class testSpider(InitSpider):
name = 'test'
custom_settings = {
'ITEM_PIPELINES': {
'app.MyPipeline': 400
}
}
এখানে দেওয়া অন্যান্য সমাধানের ভালো, কিন্তু আমি মনে করি তারা, ধীর হতে পারে, কারণ আমরা নেই না মাকড়সা প্রতি পাইপলাইন ব্যবহার করে, এর পরিবর্তে আমরা যাচাই করছি একটি পাইপলাইন প্রত্যেক সময় একটি আইটেম ফিরিয়ে দেওয়া হয় যদি উপস্থিত থাকে (এবং কিছু কিছু ক্ষেত্রে এই পৌঁছতে পারে মিলিয়ন)।
মাকড়সা প্রতি বৈশিষ্ট্য সম্পূর্ণরূপে অক্ষম (বা সক্ষম) করার একটি ভাল উপায় 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
।
আমি কমপক্ষে চারটি পদ্ধতির কথা ভাবতে পারি:
scrapy settings
আপনার মাকড়সার প্রতিটি অনুরোধের মধ্যে পাইপলাইন সেটিংটি পরিবর্তন করুনdefault_settings['ITEM_PIPELINES']
আপনার কমান্ড বর্গের যে পাইপলাইন তালিকার জন্য আপনি চান সেই আদেশটি সংজ্ঞায়িত করুন । এই উদাহরণের লাইন 6 দেখুন ।process_item()
খালি পাইপলাইন ক্লাসে, কোন মাকড়সার বিরুদ্ধে চলছে তা পরীক্ষা করে দেখুন এবং যদি সেই মাকড়সার জন্য এটি উপেক্ষা করা উচিত হয় তবে কিছুই করবেন না। আপনাকে শুরু করতে মাকড়সা প্রতি সংস্থান ব্যবহার করে উদাহরণ দেখুন । (এটি কুৎসিত সমাধানের মতো বলে মনে হচ্ছে কারণ এটি মাকড়সা এবং আইটেম পাইপলাইনগুলি দৃ tight়ভাবে সংযুক্ত করে You আপনার সম্ভবত এটি ব্যবহার করা উচিত নয়))আপনি ঠিক এইভাবে মাকড়সার ভিতরে আইটেম পাইপলাইন সেটিংস সেট করতে পারেন:
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
সর্বাধিক সহজ এবং কার্যকর সমাধান হ'ল প্রতিটি মাকড়সার মধ্যেই কাস্টম সেটিংস সেট করা।
custom_settings = {'ITEM_PIPELINES': {'project_name.pipelines.SecondPipeline': 300}}
এর পরে আপনার সেগুলি সেটিংস.পাই ফাইলে সেট করা দরকার
ITEM_PIPELINES = {
'project_name.pipelines.FistPipeline': 300,
'project_name.pipelines.SecondPipeline': 400
}
সেভাবে প্রতিটি মাকড়সাড়ু সম্পর্কিত পাইপলাইন ব্যবহার করবে।
সহজ তবে তবুও দরকারী সমাধান।
স্পাইডার কোড
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')
আশা করি এটি কারও জন্য কিছুটা সময় সাশ্রয় করবে!
আমি দুটি পাইপলাইন ব্যবহার করছি, একটি চিত্র ডাউনলোডের জন্য (মাইআইমেজপাইপলাইন) এবং দ্বিতীয়টি মংডব (মঙ্গো পাইপলাইন) -এ ডেটা সংরক্ষণের জন্য।
ধরুন আমাদের অনেক মাকড়সা রয়েছে (স্পাইডার 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