2017-04-14 12 views
0

私のパイプラインprocess_itemは、2つの異なるcsvファイルに書き込みますが、同時に外部のSOAP要求も行います。Python Scrapy断続的に実行中のパイプライン

これらのファイルは、ほとんどの時間は書き込まれないことがあります。クロールコマンドを実行すると、scrapy crawl partsまたはscrapy crawl parts -o results.jsonが実行されます。私がresults.jsonに出たら、常に結果が出ます。

非常にランダムなようです。場合によっては、パイプラインがファイルを作成することもあります。ここで

は私のパイプラインです:

# -*- coding: utf-8 -*- 
import scrapy 
import html 
import json 
from bs4 import BeautifulSoup 
from urllib.parse import urlparse 


class PartsSpiderPySpider(scrapy.Spider): 
    name = "parts" 
    allowed_domains = ["XXX"] 
    start_urls = ['https://XXX/'] 

    def parse(self, response): 
     data = {'UserName': 'XXX', 'Password': 'XXX'} 
     return scrapy.http.FormRequest(
      url='https://XXX/UserLogin/DoLogin', 
      callback=self.after_login, 
      formdata=data 
     ) 

    def after_login(self, response): 
     for i in range(1, 34): 
      request = scrapy.Request(
       url='https://XXX/Landing/AppendMoreParts?type=1&page=' + str(i), 
       callback=self.get_parts, 
      ) 
      yield request 

    def get_parts(self, response): 
     res = json.loads(response.body_as_unicode()) 
     soup = BeautifulSoup(html.unescape(res['HTMLForGeneral']), 'html.parser') 

     for part in soup.findAll('li'): 
      item = { 
       'partNumber': part.h5.a.string, 
       'make': part.findAll('span')[0].string 
      } 
      yield scrapy.Request(
       url='https://XXX/Product/ProductImageListPartial?part=' + str(item['partNumber']) + '&make=' + str(item['make']), 
       callback=self.get_img_urls, 
       meta={'item': item}, 
      ) 

    def get_cross_info(self, response): 
     item = response.meta['item'] 
     item['crossReference'] = response.css('span span::text').extract() 

     yield scrapy.Request(
      url='https://XXX/Product/GetPartModelPaging?make=' + str(item['make']) + '&partNumber=' + str(item['partNumber']), 
      callback=self.get_related_models, 
      meta={'item': item}, 
     ) 

    def get_related_models(self, response): 
     item = response.meta['item'] 
     res = json.loads(response.body_as_unicode()) 
     if res['Result']: 
      soup = BeautifulSoup(html.unescape(res['Message']), 'html.parser') 
      models = [] 
      for model in soup.findAll('a'): 
       models.append(model.string) 

      item['models'] = models 
      return item 

    def get_img_urls(self, response): 
     item = response.meta['item'] 
     soup = BeautifulSoup(response.body, 'html.parser') 
     imgs = [] 
     for div in soup.findAll('div', {'class': 'tumbimagepart'}): 
      url = div.img['src'] 
      o = urlparse(url) 
      imgs.append(o.scheme + "://" + o.netloc + o.path + '?width=750&mode=crop') 

     item['image_urls'] = imgs 

     yield scrapy.Request(
      url='https://XXX/Product/CrossReferencePartInfo?make=' + str(item['make']) + '&partNumber=' + str(item['partNumber']), 
      callback=self.get_cross_info, 
      meta={'item': item}, 
     ) 

更新パイプライン:: - - コーディング #:

一部の情報は、クローラ

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

# Define your item pipelines here 
# 
# Don't forget to add your pipeline to the ITEM_PIPELINES setting 
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html 
import csv 
import zeep 
from XXX import settings 

class XXXPipeline(object): 
    def process_item(self, item, spider): 
     data = make_request(item) 
     if (data): 
      mainCsv = csv.writer(open(settings.csv_file_path, 'a+'), delimiter=',') 
      imgPath = '/' + item['images'][0]['path'] 

      mainCsv.writerow([ 
       item['partNumber'], # sku, 
       'simple', # _type 
       'base', # _product_websites 
       'Default', # _attribute_set 
       4, # visiblity 
       1, # status 
       1, # is_in_stock 
       10, # qty 
       2, # tax_class_id 
       1, # weight 
       item['partNumber'] + data.PartDescription, # name 
       9999, # price 
       item['partNumber'] + ' ' + data.PartDescription, # description 
       item['partNumber'] + ' ' + data.PartDescription, # short_description 
       item['make'], # manufacturer_code 
       imgPath, # image 
       imgPath, # small_image 
       imgPath, # thumbnail 
       '"2,3"', # category_ids // Change based on site's categories 
      ]) 

      imgCsv = csv.writer(open(settings.img_csv_file_path, 'a+'), delimiter=',') 

      iterimg = iter(item['images']) 
      next(iterimg) 
      for img in iterimg: 
       imgCsv.writerow([ 
        item['partNumber'], 
        '/' + img['path'] 
       ]) 

     return item 

def make_request(item): 
    wsdl = 'XXX' 
    client = zeep.Client(wsdl=wsdl) 
    try: 
     data = client.service.ExactPartLookup(
      userName='XXX', 
      password='XXX', 
      make=item['make'], 
      partNumber=item['partNumber'] 
     ) 

     return data.PartInformation_v2[0] 
    except: 
     pass 

を省略されているUTF-8から -

# Define your item pipelines here 
# 
# Don't forget to add your pipeline to the ITEM_PIPELINES setting 
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html 
import csv 
import zeep 
from XXX import settings 

class XXXPipeline(object): 
    # def from_crawler(cls, crawler): 
    #  self.settings = crawler.settings 
    #  return cls() 

    def spider_open(self, spider): 
     self.data_file = open(settings.csv_file_path, 'a+') 
     self.data_writer = csv.writer(self.data_file, delimiter=',') 
     self.img_file = open(settings.img_csv_file_path, 'a+') 
     self.img_writer = csv.writer(self.img_file, delimiter=',') 

    def process_item(self, item, spider): 
     data = make_request(item) 
     if (data): 
      mainCsv = self.data_writer 
      imgPath = '/' + item['images'][0]['path'] 

      mainCsv.writerow([ 
       item['partNumber'], # sku, 
       'simple', # _type 
       'base', # _product_websites 
       'Default', # _attribute_set 
       4, # visiblity 
       1, # status 
       1, # is_in_stock 
       10, # qty 
       2, # tax_class_id 
       1, # weight 
       item['partNumber'] + data.PartDescription, # name 
       9999, # price 
       item['partNumber'] + ' ' + data.PartDescription, # description 
       item['partNumber'] + ' ' + data.PartDescription, # short_description 
       item['make'], # manufacturer_code 
       imgPath, # image 
       imgPath, # small_image 
       imgPath, # thumbnail 
       '"2,3"', # category_ids // Change based on site's categories 
      ]) 

      imgCsv = self.img_writer 

      iterimg = iter(item['images']) 
      next(iterimg) 
      for img in iterimg: 
       imgCsv.writerow([ 
        item['partNumber'], 
        '/' + img['path'] 
       ]) 

     return item 

    def spider_close(self, spider): 
     self.data_file.close() 
     self.image_file.close() 

def make_request(item): 
    wsdl = 'https://XXX/b2b/parts_v2.asmx?WSDL' 
    client = zeep.Client(wsdl=wsdl) 
    # try: 
    data = client.service.ExactPartLookup(
     userName='XXX', 
     password='XXX', 
     make=str(item['make']), 
     partNumber=str(item['partNumber']) 
    ) 

    return data.PartInformation_v2[0] 
    # except: 
    #  raise Exception('Couldn\'t get part information!') 

編集:maximum recursion depth exceeded while getting the str of an object

機能make_requestが呼び出されたときに、私はこのエラーを取得していようだ:私は私の問題が原因このエラーに実際にあることを発見しました。これが起こる原因は何かを完全には理解していません。

答えて

2

パイプラインの初期化中にファイルを開く必要があります。治療パイプラインは便利なメソッドspider_open()を持っています。これはのinitのように動作しますが、スパイダーが起動したときにのみ - 何らかの場合は何もしません。

だから、あなたがしたい:

  1. クモが開いたら - クモが閉じると行
  2. など、すべての項目を書く - - あなたをクローズアップクモを実行するとすると、あなたのファイルを開くと、作成したCSVライターが
  3. オブジェクトファイル

注意すべきもう一つの重要なことはscrapyは、さまざまな場所リーで設定を行うことができるので、あなたが、crawlerからsettingsオブジェクトを取得する必要があるということですシェル経由で(scrapy crawl myspider -s CSV_FILE_LOCATION=/home/me/something.csvのように)私は私のプロジェクトにこれらの変更で追加した

class MyPipeline: 

    @classmethod 
    def from_crawler(cls, crawler) 
     # you want to get settings from crawler because settings.py is 
     # not the only place that can have some settings 
     self.settings = crawler.settings 
     return cls() 

    def open_spider(self, spider): 
     # initiate file and writer objects once the spider opens 
     self.data_file = open(self.settings.get('CSV_DATA'), 'a+') 
     self.data_writer = csv.writer(self.data_file) 
     self.image_file = open(settings.get('CSV_IMAGE'), 'a+') 
     self.image_writer = csv.writer(self.image_file) 

    def process_item(self, item, spider): 
     # write some rows! 
     if 'image' in item: 
      self.image_writer.write_row(item.values() 
     else: 
      self.data_writer.write_row(item.values()) 
     return item 

    def close_spider(self, spider): 
     # close the file objects 
     self.data_file.close() 
     self.image_file.close() 
+0

このすべてが一緒に置くには、この線に沿って何かを探して終わる必要があります。しかし、それはまだ動作していません。私はそれが実際に別の問題であることを知りました。あなたの質問を更新する必要がありますか?私の 'make_request'メソッドは何も返さないようです。私は 'オブジェクトのstrを取得中に'最大再帰深度を超えています 'エラー –

+0

@RyanScottCadyこのエラーの完全なトレースバックを投稿できますか? – Granitosaurus

+0

これは、リクエスト内のデータに 'str()'を使って修正したと思います。 'AttributeError: 'XXXPipeline'オブジェクトに 'data_writer'属性がありません –

関連する問題