Tôi có một dự án trị liệu chứa nhiều nhện. Có cách nào tôi có thể xác định đường ống dẫn để sử dụng cho con nhện nào không? Không phải tất cả các đường ống mà tôi đã xác định đều có thể áp dụng cho mọi mạng nhện.
Cảm ơn
Tôi có một dự án trị liệu chứa nhiều nhện. Có cách nào tôi có thể xác định đường ống dẫn để sử dụng cho con nhện nào không? Không phải tất cả các đường ống mà tôi đã xác định đều có thể áp dụng cho mọi mạng nhện.
Cảm ơn
Câu trả lời:
Dựa trên giải pháp từ Pablo Hoffman , bạn có thể sử dụng trình trang trí sau trên process_item
phương thức của một đối tượng Pipeline để nó kiểm tra pipeline
thuộc tính của spider của bạn xem nó có nên được thực thi hay không. Ví dụ:
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
Để trình trang trí này hoạt động chính xác, con nhện phải có thuộc tính đường ống với một vùng chứa các đối tượng Đường ống mà bạn muốn sử dụng để xử lý mặt hàng, ví dụ:
class MySpider(BaseSpider):
pipeline = set([
pipelines.Save,
pipelines.Validate,
])
def parse(self, response):
# insert scrapy goodness here
return item
Và sau đó trong một pipelines.py
tệp:
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
Tất cả các đối tượng Pipeline vẫn phải được xác định trong ITEM_PIPELINES trong cài đặt (theo đúng thứ tự - sẽ rất tốt nếu thay đổi để thứ tự cũng có thể được chỉ định trên Spider).
scrapy crawl <spider name>
lệnh. python không nhận ra tên tôi đặt trong lớp spider để các đường ống chạy. Tôi sẽ cung cấp cho bạn liên kết đến tôi spider.py và pipeline.py để bạn có thể có một cái nhìn. Cảm ơn
spider.py
bên phải?
if not hasattr(spider, 'pipeline') or self.__class__ in spider.pipeline:
Chỉ cần xóa tất cả các đường ống dẫn khỏi cài đặt chính và sử dụng spider bên trong này.
Điều này sẽ xác định đường dẫn đến người dùng trên mỗi con nhện
class testSpider(InitSpider):
name = 'test'
custom_settings = {
'ITEM_PIPELINES': {
'app.MyPipeline': 400
}
}
Các giải pháp khác được đưa ra ở đây là tốt, nhưng tôi nghĩ chúng có thể chậm, bởi vì chúng tôi không thực sự không sử dụng đường ống cho mỗi con nhện, thay vào đó chúng tôi đang kiểm tra xem đường ống có tồn tại mỗi khi một mặt hàng được trả lại hay không (và trong một số trường hợp, điều này có thể đạt được hàng triệu).
Một cách tốt để tắt hoàn toàn (hoặc bật) một tính năng mà mỗi con nhện đang sử dụng custom_setting
và from_crawler
cho tất cả các tiện ích mở rộng như sau:
pipelines.py
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
settings.py
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
}
Khi bạn kiểm tra, chúng tôi đã chỉ định custom_settings
điều đó sẽ ghi đè những thứ được chỉ định trong settings.py
và chúng tôi đang vô hiệu hóa trình thu thập dữ liệu SOMEPIPELINE_ENABLED
này.
Bây giờ khi bạn chạy con nhện này, hãy kiểm tra một cái gì đó như:
[scrapy] INFO: Enabled item pipelines: []
Bây giờ liệu pháp đã hoàn toàn vô hiệu hóa đường ống, không bận tâm đến sự tồn tại của nó trong suốt quá trình. Kiểm tra xem điều này cũng có tác dụng đối với liệu pháp extensions
và middlewares
.
Tôi có thể nghĩ ra ít nhất bốn cách tiếp cận:
scrapy settings
giữa mỗi lần gọi nhện của bạndefault_settings['ITEM_PIPELINES']
trên lớp lệnh của bạn thành danh sách đường ống mà bạn muốn cho lệnh đó. Xem dòng 6 của ví dụ này .process_item()
hãy kiểm tra xem nó đang chống lại con nhện nào và không làm gì nếu nên bỏ qua con nhện đó. Xem ví dụ về cách sử dụng tài nguyên trên mỗi con nhện để giúp bạn bắt đầu. (Đây có vẻ là một giải pháp xấu vì nó kết hợp chặt chẽ giữa nhện và đường ống dẫn vật phẩm. Bạn có thể không nên sử dụng giải pháp này.)Bạn có thể sử dụng name
thuộc tính của con nhện trong đường dẫn của mình
class CustomPipeline(object)
def process_item(self, item, spider)
if spider.name == 'spider1':
# do something
return item
return item
Xác định tất cả các đường ống theo cách này có thể đạt được những gì bạn muốn.
Bạn chỉ có thể đặt cài đặt đường ống mục bên trong spider như sau:
class CustomSpider(Spider):
name = 'custom_spider'
custom_settings = {
'ITEM_PIPELINES': {
'__main__.PagePipeline': 400,
'__main__.ProductPipeline': 300,
},
'CONCURRENT_REQUESTS_PER_DOMAIN': 2
}
Sau đó, tôi có thể chia nhỏ một đường ống (hoặc thậm chí sử dụng nhiều đường ống) bằng cách thêm một giá trị vào trình tải / mục trả về để xác định phần nào của trình thu thập dữ liệu đã gửi các mục qua. Bằng cách này, tôi sẽ không nhận được bất kỳ ngoại lệ KeyError nào và tôi biết những mục nào sẽ có sẵn.
...
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
Giải pháp đơn giản nhưng vẫn hữu ích.
Mã nhện
def parse(self, response):
item = {}
... do parse stuff
item['info'] = {'spider': 'Spider2'}
mã đường ống
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')
Hy vọng điều này tiết kiệm thời gian cho ai đó!
Tôi đang sử dụng hai đường dẫn, một để tải xuống hình ảnh (MyImagesPipeline) và thứ hai để lưu dữ liệu trong mongodb (MongoPipeline).
giả sử chúng ta có nhiều nhện (spider1, spider2, ...........), trong ví dụ của tôi, spider1 và spider5 không thể sử dụng MyImagesPipeline
settings.py
ITEM_PIPELINES = {'scrapycrawler.pipelines.MyImagesPipeline' : 1,'scrapycrawler.pipelines.MongoPipeline' : 2}
IMAGES_STORE = '/var/www/scrapycrawler/dowload'
Và mã hoàn chỉnh dưới đây của đường ống
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
Giải pháp đơn giản và hiệu quả nhất là đặt cài đặt tùy chỉnh trong chính mỗi con nhện.
custom_settings = {'ITEM_PIPELINES': {'project_name.pipelines.SecondPipeline': 300}}
Sau đó, bạn cần đặt chúng trong tệp settings.py
ITEM_PIPELINES = {
'project_name.pipelines.FistPipeline': 300,
'project_name.pipelines.SecondPipeline': 300
}
theo cách đó, mỗi con nhện sẽ sử dụng đường ống tương ứng.