2014-11-24 3 views
0

안녕하세요, 저는 파이썬과 스콥에 매우 익숙합니다.이 코드는 제 첫 번째 코드이며, 기본적인 문제는 해결할 수 없습니다.파이프 라인에 여러 항목 클래스를 전달하는 스 크리 쳐 크롤러

나는 두 가지를 할 수있는 크롤러 설정 : 1은 모든 매김 URL을 찾기를 방문하고 각 페이지에서 일부 데이터를 얻을 수를 2, 결과 페이지에 나열된 모든 링크를 얻을 각 위치에 그들과 크롤링을 visite에 데이터

콜백 규칙을 사용하여 구문 분석 할 각 항목의 결정을 내리고 있습니다. 각 파서에 대해 items.py 클래스를 만들었습니다

두 번째 규칙은 완벽하게 처리되지만 첫 번째 처리가 진행되지 않고 오류 위치를 찾을 수 없습니다.

내가 오류 메시지를 보면 크롤러

2014-11-24 02:30:39-0200 [apontador] ERROR: Error processing {'city': u'BR-SP-S\xe3o Paulo', 
    'coordinates': {'lat': u'-23.56588', 'lng': u'-46.64777'}, 
    'current_url': 'http://www.apontador.com.br/local/search.html?q=supermercado&loc_z=S%C3%A3o+Paulo%2C+SP&loc=S%C3%A3o+Paulo%2C+SP&loc_y=S%C3%A3o+Paulo%2C+SP', 
    'datetime': datetime.datetime(2014, 11, 24, 2, 30, 39, 703972), 
    'depth': 0, 
    'domain': 'apontador.com.br', 
    'link_cat': 'ls', 
    'loc_cat': u'supermercado', 
    'session_id': -1, 
    'site_name': u'Apontador', 
    'state': u'BR-SP'} 
    Traceback (most recent call last): 
     File "/usr/local/lib/python2.7/dist-packages/scrapy/middleware.py", line 62, in _process_chain 
     return process_chain(self.methods[methodname], obj, *args) 
     File "/usr/local/lib/python2.7/dist-packages/scrapy/utils/defer.py", line 65, in process_chain 
     d.callback(input) 
     File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 382, in callback 
     self._startRunCallbacks(result) 
     File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 490, in _startRunCallbacks 
     self._runCallbacks() 
    --- <exception caught here> --- 
     File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 577, in _runCallbacks 
     current.result = callback(current.result, *args, **kw) 
     File "/locman/scrapy/locman/pipelines.py", line 37, in process_item 
     'neighborhood': item['neighborhood'], 
    File "/usr/local/lib/python2.7/dist-packages/scrapy/item.py", line 50, in __getitem__ 
     return self._values[key] 
    exceptions.KeyError: 'neighborhood' 

을 실행하는 터미널에서 무엇입니까 오류 메시지가 scrapy가 items.py의 모든 항목을 처리하는 것이 분명 보인다, 정의 된 항목 클래스를 존중하지 각 콜백에 의해 호출됩니다. 1 apontadorlsItem, 2 apontadordsItem

apontadordsItem 키 '이웃'하지만 항목 클래스가 apontadorlsItem 키 '이웃'이없는있다 클래스 : 당신이 파일이 있으면

는 두 개의 클래스가 있습니다 items.py . xpath 규칙에 따라 두 개의 다른 콜백 파서 함수를 지원하기 위해이 두 클래스를 만들었습니다. 각 페이지마다 서로 다른 정보 세트로 크롤링되는 두 가지 유형의 페이지가 있기 때문에이 작업을 수행했습니다. 로그 파일에서 볼 수있는 규칙이 제대로 작동하고 크롤러가 작동하며 문제가 처리 중이거나 저장 중입니다!

크롤러가 사용한 소스 items.py 클래스에 따라 파이프 라인을 사용하여 다른 항목 일치 규칙을 사용하도록 어떻게 선언 할 수 있습니까? apontador.py

import scrapy 
from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor 
from scrapy.selector import HtmlXPathSelector 
from scrapy.selector import Selector 
from datetime import datetime 
from tld import get_tld 
from locman.items import apontadorlsItem 
from locman.items import apontadordsItem 

class apontador(CrawlSpider): 
    name = 'apontador' 
    session_id = -1 
    start_urls = ["http://www.apontador.com.br/local/search.html?q=supermercado&loc_z=S%C3%A3o+Paulo%2C+SP&loc=S%C3%A3o+Paulo%2C+SP&loc_y=S%C3%A3o+Paulo%2C+SP"] 
    rules = (
      # Rule for LS - Link source - Search results page 
      Rule(SgmlLinkExtractor(allow=("",),restrict_xpaths=("//nav[@class='pagination']")), callback='parse_items_ls', follow= True), 

      # Rule for DS - Data Source - Location data page 
      Rule(SgmlLinkExtractor(allow=("",),restrict_xpaths=(
       "//article[@class='poi card highlight']", 
       "//li[@class='similar-place sponsored']", 
       "//div[@class='recomendations']", 
       "//ul[@class='similar-places-list']", 
       "//article[@class='poi card']")), 
       callback='parse_items_ds', 
       follow= True), 
    ) 

    def __init__(self, session_id=-1, *args, **kwargs): 
     super(apontador, self).__init__(*args, **kwargs) 
     self.session_id = session_id 

    def parse_start_url(self, response): 
     self.response_url = response.url 
     return self.parse_items_ls(response) 

    # Callback item type LS 
    def parse_items_ls(self, response): 
     self.response_url = response.url 
     sel = Selector(response) 
     items_ls = [] 
     item_ls = apontadorlsItem() 
     item_ls["session_id"] = self.session_id 
     item_ls["depth"] = response.meta["depth"] 
     item_ls["current_url"] = response.url 

    # Get site name in metadata 
     meta_site = sel.xpath("//meta[@property='og:site_name']/@content").extract() 
     item_ls["site_name"] = u''.join(meta_site) 

    # Get latitude and longitude in metadata 
     meta_latitude = sel.xpath("//meta[@name='apontador:latitude']/@content").extract() 
     latitude = ''.join(meta_latitude) 

     meta_longitude = sel.xpath("//meta[@name='apontador:longitude']/@content").extract() 
     longitude = ''.join(meta_longitude) 

    # Convert the coordinates to an array 
     coordinates = {"lng": longitude , "lat": latitude} 
     item_ls["coordinates"] = coordinates 

    # This items gets the strings directly from meta data keywords and creates a list 
     meta_keywords_ls = sel.xpath("//meta[@name='keywords']/@content").extract() 
     meta_keywords_ls_str = u''.join(meta_keywords_ls) 
     meta_keywords_ls_list = meta_keywords_ls_str.split(", ") 
     meta_state = meta_keywords_ls_list[6] 
     meta_city = meta_keywords_ls_list[5] 
     meta_loc_cat = meta_keywords_ls_list[4] 

     item_ls["state"] = u"BR-" + meta_state 
     item_ls["city"] = u"BR-" + meta_state + "-" + meta_city 
     item_ls["loc_cat"] = meta_loc_cat 

    # This items gets the domain name using the TLD module 
     domain = get_tld(response.url) 
     item_ls["domain"] = domain 

    # This items gets datetime 
     item_ls["datetime"] = datetime.now() 

    # This items defines de link category   
     item_ls["link_cat"] = "ls" 
     yield item_ls 


    # Callback item type DS 
    def parse_items_ds(self, response): 
     self.response_url = response.url 
     sel = Selector(response) 
     items_ds = [] 
     item_ds = apontadordsItem() 
     item_ds["session_id"] = self.session_id 
     item_ds["depth"] = response.meta["depth"] 
     item_ds["current_url"] = response.url 

    # Get site name in metadata 
     meta_site = sel.xpath("//meta[@property='og:site_name']/@content").extract() 
     item_ds["site_name"] = u''.join(meta_site) 

    # Get location name in metadata 
     meta_loc_name = sel.xpath("//meta[@property='og:title']/@content").extract() 
     item_ds["loc_name"] = u''.join(meta_loc_name) 

    # Get location source id in metadata 
     meta_loc_source_id = sel.xpath("//meta[@name='apontador:place-id']/@content").extract() 
     item_ds["loc_source_id"] = ''.join(meta_loc_source_id) 

    # Get location street address in metadata 
     meta_loc_address = sel.xpath("//meta[@property='business:contact_data:street_address']/@content").extract() 
     meta_loc_address_str = u''.join(meta_loc_address) 
     meta_loc_address_list = meta_loc_address_str.split(", ") 
     meta_loc_address_number = meta_loc_address_list[1] 
     meta_loc_address_street = meta_loc_address_list[0] 
     item_ds["loc_street"] = meta_loc_address_street 
     item_ds["loc_number"] = meta_loc_address_number 

    # Get latitude and longitude in metadata 
     meta_latitude = sel.xpath("//meta[@property='place:location:latitude']/@content").extract() 
     latitude = ''.join(meta_latitude) 

     meta_longitude = sel.xpath("//meta[@property='place:location:longitude']/@content").extract() 
     longitude = ''.join(meta_longitude) 

     coordinates = {"lng": longitude , "lat": latitude} 
     item_ds["coordinates"] = coordinates 

    # This items gets the neighborhood, loc_cat, loc_sub_categoryfrom meta data keywords, creates a list and populates the fields from the list 
     meta_keywords_ds = sel.xpath("//meta[@name='keywords']/@content").extract() 
     meta_keywords_ds_str = u''.join(meta_keywords_ds) 
     meta_keywords_ds_list = meta_keywords_ds_str.split(", ") 
     meta_loc_cat = meta_keywords_ds_list[9] 
     meta_loc_cat_sub = meta_keywords_ds_list[8] 
     meta_neighborhood = meta_keywords_ds_list[5] 

     item_ds["loc_cat"] = meta_loc_cat 
     item_ds["loc_cat_sub"] = meta_loc_cat_sub 
     item_ds["neighborhood"] = meta_neighborhood 

    # Region informations 
     meta_statec = sel.xpath("//meta[@property='business:contact_data:region']/@content").extract() 
     meta_state = u''.join(meta_statec) 
     item_ds["state"] = u"BR-" + meta_state 

     meta_cityc = sel.xpath("//meta[@property='business:contact_data:locality']/@content").extract() 
     meta_city = u''.join(meta_cityc) 
     item_ds["city"] = u"BR-" + meta_state + "-" + meta_city 

     meta_postal_code = sel.xpath("//meta[@property='business:contact_data:postal_code']/@content").extract() 
     item_ds["loc_postal_code"] = ''.join(meta_postal_code) 

    # This items gets the domain name using the TLD module 
     domain = get_tld(response.url) 
     item_ds["domain"] = domain 

    # This items gets datetime as an i 
     item_ds["datetime"] = datetime.now() 

     item_ds["link_cat"] = "ds" 
     yield item_ds 

항목은 파일/거미 - - items.py가

from scrapy.item import Item, Field 

class apontadorlsItem(Item): 
    datetime = Field() 
    session_id = Field() 
    depth = Field() 
    link_cat = Field() 
    site_name = Field() 
    domain = Field() 
    current_url = Field() 
    city = Field() 
    state = Field() 
    loc_cat = Field() 
    coordinates = Field() 

class apontadordsItem(Item): 
    datetime = Field() 
    session_id = Field() 
    depth = Field() 
    link_cat = Field() 
    site_name = Field() 
    domain = Field() 
    current_url = Field() 
    state = Field() 
    city = Field() 
    neighborhood = Field() 
    loc_name = Field() 
    loc_street = Field() 
    loc_number = Field() 
    loc_postal_code = Field() 
    loc_source_id = Field() 
    loc_cat = Field() 
    loc_cat_sub = Field() 
    coordinates = Field() 

파이프 라인 파일 - pipelines.py

내가

스파이더 파일

붙어있어, 도와주세요
from scrapy.exceptions import DropItem 
from scrapy_mongodb import MongoDBPipeline 

class apontadorpipe(MongoDBPipeline): 

    def process_item(self, item, spider): 
     if self.config['buffer']: 
      self.current_item += 1 
      item = dict(item) 

      self.item_buffer.append(item) 

      if self.current_item == self.config['buffer']: 
       self.current_item = 0 
       return self.insert_item(self.item_buffer, spider) 
      else: 
       return item 

     matching_item = self.collection.find_one(
      {'datetime': item['datetime'], 
      'session_id': item['session_id'], 
      'depth': item['depth'], 
      'link_cat': item['link_cat'], 
      'site_name': item['site_name'], 
      'domain': item['domain'], 
      'current_url': item['current_url'], 
      'state': item['state'], 
      'city': item['city'], 
      'neighborhood': item['neighborhood'], 
      'loc_name': item['loc_name'], 
      'loc_street': item['loc_street'], 
      'loc_number': item['loc_number'], 
      'loc_postal_code': item['loc_postal_code'], 
      'loc_cat': item['loc_cat'], 
      'loc_cat_sub': item['loc_cat_sub'], 
      'loc_source_id': item['loc_source_id'], 
      'coordinates': item['coordinates']} 
     ) 

     if matching_item is not None: 
      raise DropItem(
       "Duplicate found for %s, %s" % 
       item['current_url'] 
      ) 
     else: 
      return self.insert_item(item, spider) 

설정 파일 - settings.py

BOT_NAME = 'locman' 

SPIDER_MODULES = 'locman.spiders' 
NEWSPIDER_MODULE = 'locman.spiders' 
DEPTH_LIMIT = 10000 

DEFAULT_ITEM_CLASS = 'locman.items.apontador' 

ITEM_PIPELINES = { 
    'locman.pipelines.apontadorpipe': 100 
} 

# 'scrapy_mongodb.MongoDBPipeline' connection 
MONGODB_URI = 'connection string' 
MONGODB_DATABASE = '' 
MONGODB_COLLECTION = '' 

DOWNLOADER_MIDDLEWARES = { 
     'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware' : None, 
     'locman.ua.rotate_useragent.RotateUserAgentMiddleware' :400 
    } 
+0

당신이()'콜백 'parse_items_ls에서 나오는 항목을 저장 하시겠습니까? – alecxe

+0

예 item.py의 클래스 apontadorlsItem을 사용하여 parse_items_ls()의 항목을 저장하고 싶습니다. –

+0

parse_items_ds()는 mongoDB에 데이터를 저장하고 있지만 items.py의 클래스 apontadordsem을 사용하고 있는지 확실하지 않습니다. –

답변

0

"이웃"키가없는 것 같습니다. 다음과 같은 것들을 확인하십시오.

  1. 당신은 "이웃"맞춤법이 틀린하지 않은
  2. "이웃"이다는
  3. 항목 [ '이웃'] 거미에 초기화

해당 항목이 "키가 있는지 확인 항목 클래스에 정의 파일/locman/scrapy/locman/파이프 라인에서 "이웃"을 찾습니다.이웃 평 당신은 또한

if item.get('neighborhood', 'default_value') 
+0

안녕하세요 Tasawer, 내가 제안한 내용을 모두 확인했는데 그 중 하나를 찾지 못했습니다! 거미가 데이터를 얻고 있습니다. 문제는 mongodb에 쓸 때 파이프 라인에 있다고 생각합니다. –

+0

두 개 이상의 항목이있을 수 있습니다. 따라서 항목 중 일부가 "이웃"값을 가지지 않았고 항목 [ "인근 지역] 값을 가져 오기 전에 수표를 추가 할 가능성이 있습니다. 내 대답 모양이 개선되었습니다 .. 감사합니다. –

+0

안녕하세요 .. 도움/조언을 주셔서 감사합니다. 시험해보고 결과를 알려 드리겠습니다. –

0

덕분에 많은 위해를 대신 같은 없음의 디폴트 값을 설정할 수 있습니다 ","항목이없는 키가있는 경우 process_item에서, 라인 (37)은,

if item.get('neighborhood', None): 

이 없음을 반환하지 않습니다 " 도움이! 내 문제에 대한 좋은 workround 발견하고 정확히 내가 무엇을 필요가 무엇입니까!

에서 pipeline.py 내가 items.py에서 두 개의 클래스를 가져 오면, 각각 다른 기능을 정의하고 각각에 대해 dict. 다른 중복 기록 처리 및 서로 다른 쓰기 프로세스를 가질 수 있습니다. 그는 각 항목 클래스에 대한 데이터베이스!

pipeline.py위한 새로운 코드 :

from scrapy.exceptions import DropItem 
from scrapy_mongodb import MongoDBPipeline 

from locman.items import apontadorlsItem 
from locman.items import apontadordsItem 

class apontadorpipe(MongoDBPipeline): 

def process_item_ds(self, item, spider): 
    if self.config['buffer']: 
     self.current_item += 1 
     item = dict(apontadordsItem) 

     self.item_buffer.append(item) 

     if self.current_item == self.config['buffer']: 
      self.current_item = 0 
      return self.insert_item(self.item_buffer, spider) 
     else: 
      return item 

     if isinstance(item, apontadordsItem): 
      matching_item = self.collection.find_one(
       {'datetime': item['datetime'], 
       'session_id': item['session_id'], 
       'link_cat': item['link_cat'], 
       'site_name': item['site_name'].encode('utf-8'), 
       'domain': item['domain'], 
       'current_url': item['current_url'], 
       'state': item['state'], 
       'city': item['city'].encode('utf-8'), 
       'neighborhood': item['neighborhood'].encode('utf-8'), 
       'loc_name': item['loc_name'].encode('utf-8'), 
       'loc_street': item['loc_street'].encode('utf-8'), 
       'loc_number': item['loc_number'], 
       'loc_postal_code': item['loc_postal_code'], 
       'loc_cat': item['loc_cat'], 
       'loc_cat_sub': item['loc_cat_sub'], 
       'loc_source_id': item['loc_source_id'], 
       'loc_phone': item['loc_phone'], 
       'address': item['address'].encode('utf-8'), 
       'coordinates': item['coordinates']} 
      ) 

      if matching_item is not None: 
       raise DropItem(
        "Duplicate found for %s, %s" % 
        item['current_url'], 
        item['loc_source_id'], 
       ) 

      else: 

       return self.insert_item(item, spider) 


def process_item_ls(self, item, spider): 
    if self.config['buffer']: 
     self.current_item += 1 
     item = dict(apontadorlsItem) 

     self.item_buffer.append(item) 

     if self.current_item == self.config['buffer']: 
      self.current_item = 0 
      return self.insert_item(self.item_buffer, spider) 
     else: 
      return item 

     if isinstance(item, apontadorlsItem): 
      matching_item = self.collection.find_one(
       {'datetime': item['datetime'], 
       'session_id': item['session_id'], 
       'link_cat': item['link_cat'], 
       'site_name': item['site_name'].encode('utf-8'), 
       'domain': item['domain'], 
       'current_url': item['current_url'], 
       'state': item['state'], 
       'city': item['city'].encode('utf-8'), 
       'loc_cat': item['loc_cat'].encode('utf-8'), 
       'coordinates': item['coordinates']} 
      ) 

      if matching_item is not None: 
       raise DropItem(
        "Duplicate found for %s, %s" % 
        item['current_url'], 
       ) 

      else: 

       return self.insert_item(item, spider) 
관련 문제