2016-03-02 19 views
0

Я хочу сделать сканер, который начинается с URL-адреса (стр. 1), и следует по ссылке на новую страницу, стр. 2. На стр. 2 он должен следовать ссылке на страницу 3. Затем я хочу очистить некоторые данные на стр. 3.Функция обратного вызова Scrapy, как разобрать несколько страниц?

Тем не менее, я нахожусь на сбое и не могу заставить функцию обратного вызова работать. Вот мой код:

class allabolagnewspider(CrawlSpider): 
name="allabolagnewspider" 
# allowed_domains = ["byralistan.se"] 
start_urls = [ 
    "http://www.allabolag.se/5565794400/befattningar" 
] 

rules = (
    Rule(LinkExtractor(allow = "http://www.allabolag.se", 
         restrict_xpaths=('//*[@id="printContent"]//a[1]'), 
         canonicalize=False), 
     callback='parse_link1'), 
) 

def parse_link1(self, response): 
    hxs = HtmlXPathSelector(response) 
    return Request(hxs.xpath('//*[@id="printContent"]/div[2]/table/tbody/tr[4]/td/table/tbody/tr/td[2]/a').extract(), callback=self.parse_link2) 

def parse_link2(self, response): 
    for sel in response.xpath('//*[@id="printContent"]'): 
     item = AllabolagnewItem() 
     item['Byra'] = sel.xpath('/div[2]/table/tbody/tr[3]/td/h1').extract() 
     item['Namn'] = sel.xpath('/div[2]/table/tbody/tr[3]/td/h1').extract() 
     item['Gender'] = sel.xpath('/div[2]/table/tbody/tr[3]/td/h1').extract() 
     item['Alder'] = sel.xpath('/div[2]/table/tbody/tr[3]/td/h1').extract() 
     yield item 

Однако, когда я запускаю его я получаю следующее сообщение об ошибке: «TypeError: URL запроса должен быть Обл или юникода, получил список:»

Если я правильно понял, я беспорядок, когда я пытаюсь вернуть мой запрос для parse_link1. Что мне делать?

Edit:

Вот рабочий код (все еще есть несколько вопросов, но, хотя конкретная проблема была решена):

class allabolagnewspider(CrawlSpider): 
name="allabolagnewspider" 
# allowed_domains = ["byralistan.se"] 
start_urls = [ 
    "http://www.allabolag.se/5565794400/befattningar" 
] 

rules = (
    Rule(LinkExtractor(allow = "http://www.allabolag.se", 
         restrict_xpaths=('//*[@id="printContent"]//a[2]'), 
         canonicalize=False), 
     callback='parse_link1'), 
) 

def parse_link1(self, response): 
    for href in response.xpath('''//*[@id="printContent"]/div[2]/table//tr[4]/td/table//tr/td[2]/a/@href''').extract(): 
     print "hey" 
     yield Request(response.urljoin(href), callback=self.parse_link2) 

def parse_link2(self, response): 
    for sel in response.xpath('//*[@id="printContent"]'): 
     print "hey2" 
     item = AllabolagnewItem() 
     item['Byra'] = sel.xpath('./div[2]/table//tr[3]/td/h1/text()').extract() 
     item['Namn'] = sel.xpath('./div[2]/table//tr[3]/td/h1/text()').extract() 
     item['Gender'] = sel.xpath('./div[2]/table//tr[7]/td/table[1]//tr[1]/td/text()').extract() 
     item['Alder'] = sel.xpath('./div[2]/table//tr[3]/td/h1/text()').extract() 
     yield item 

ответ

1

В parse_link1, вы передаете список, результат .extract() на SelectorList (результат вызова .xpath() на селекторе hxs), в качестве значения для url, первый аргумент Request конструктора, в то время как одно значение, как ожидается, ,

Использование .extract_first() вместо:

return Request(hxs.xpath('//*[@id="printContent"]/div[2]/table/tbody/tr[4]/td/table/tbody/tr/td[2]/a').extract_first() 

Редактировать после OP Комментарий на

"TypeError: Request url must be str or unicode, got NoneType:" 

Это происходит из-за "слишком консервативной" выражение XPath, вероятно, дает ваш браузер Проверьте инструменты Я предполагаю (я протестировал ваш XPath в Chrome и работает на this example page)

Проблема с .../table/tbody/tr/.... Дело в том, что <tbody> редко существует для реальных HTML-страниц, написанных людьми или даже шаблонами (написанными людьми). HTML хочет, чтобы <table> имел <tbody>, но никто действительно не заботится, и браузеры отлично справляются (и они вводят недостающий элемент <tbody> для размещения строк <tr>.)

Таким образом, хотя это не совсем эквивалент XPath, обычно это прекрасно:

  • либо опустить tbody/ и использовать table/tr шаблон
  • или использовать table//tr

в действии с scrapy shell:

$ scrapy shell http://www.allabolag.se/befattningshavare/de_Sauvage-Nolting%252C_Henri_Jacob_Jan/f6da68933af6383498691f19de7ebd4b 
>>> 
>>> # with XPath from browser tool (I assume), you get nothing for the "real" downloaded HTML 
>>> response.xpath('//*[@id="printContent"]/div[2]/table/tbody/tr[4]/td/table/tbody/tr/td[2]/a') 
[] 
>>> 
>>> # or, omitting `tbody/` 
>>> response.xpath('//*[@id="printContent"]/div[2]/table/tr[4]/td/table/tr/td[2]/a') 
[<Selector xpath='//*[@id="printContent"]/div[2]/table/tr[4]/td/table/tr/td[2]/a' data=u'<a href="/befattningshavare/de_Sauvage-N'>] 

>>> # replacing "/table/tbody/" with "/table//" (tbody is added by browser to have "correct DOM tree") 
>>> response.xpath('//*[@id="printContent"]/div[2]/table//tr[4]/td/table//tr/td[2]/a') 
[<Selector xpath='//*[@id="printContent"]/div[2]/table//tr[4]/td/table//tr/td[2]/a' data=u'<a href="/befattningshavare/de_Sauvage-N'>] 
>>> 
>>> # suggestion: use the <img> tag after the <a> as predicate 
>>> response.xpath('//*[@id="printContent"]/div[2]/table//tr/td/table//tr/td/a[img/@alt="personprofil"]') 
[<Selector xpath='//*[@id="printContent"]/div[2]/table//tr/td/table//tr/td/a[img/@alt="personprofil"]' data=u'<a href="/befattningshavare/de_Sauvage-N'>] 
>>> 

Кроме того, вам нужно:

  • , чтобы получить "HREF" значение атрибута (добавление @href в конце вашего XPath)
  • построить абсолютный URL. response.urljoin() удобный ярлык для этого

Продолжаем в Scrapy оболочки:

>>> response.xpath('//*[@id="printContent"]/div[2]/table/tr[4]/td/table/tr/td[2]/a/@href').extract_first() 
u'/befattningshavare/de_Sauvage-Nolting%252C_Henri_Jacob_Jan_Personprofil/f6da68933af6383498691f19de7ebd4b' 
>>> response.urljoin(u'/befattningshavare/de_Sauvage-Nolting%252C_Henri_Jacob_Jan_Personprofil/f6da68933af6383498691f19de7ebd4b') 
u'http://www.allabolag.se/befattningshavare/de_Sauvage-Nolting%252C_Henri_Jacob_Jan_Personprofil/f6da68933af6383498691f19de7ebd4b' 
>>> 

В конце концов, ваш обратный вызов может стать:

def parse_link1(self, response): 
    # .extract() returns a list here, after .xpath() 
    # so you can loop, even if you have 1 result 
    # 
    # XPaths can be multiline, it's easier to read for long expressions 
    for href in response.xpath(''' 
     //*[@id="printContent"] 
      /div[2] 
      /table//tr[4]/td 
      /table//tr/td[2]/a/@href''').extract(): 
     yield Request(response.urljoin(href), 
         callback=self.parse_link2) 
+0

Спасибо большое. Однако теперь я получаю новую ошибку: «TypeError: Request url должен быть str или unicode, получил NoneType:« – brrrglund

+0

Спасибо за ваш обновленный ответ! Теперь он отлично переполняет связанные страницы. Однако у меня все еще возникла проблема с функцией обратного вызова «callback = self.parse_link2». Он не очищает страницу. Когда я запускаю код, он только сканирует, но не очищает сайт. У меня даже был идентичный вывод, когда я удалил всю функцию parse_link2. Правильно ли выполняю функцию обратного вызова? – brrrglund

+0

@brrrglund, в цикле над результатами вызова '.xpath()', вам нужно использовать ** относительные XPaths ** (начиная с '. /', Чтобы быть в безопасности) вместо абсолютных XPaths (начиная с '/ ') - последние начинаются с корня документа. Попробуйте 'sel.xpath ('./ div [2]/table // tr [3]/td/h1'). Extract()' (я удалил 'tbody /' тоже) –

0

hxs.xpath(...).extract() возвращает список, а не строка. Попробуйте выполнить итерацию по списку, уступая запросам, или выберите нужный URL из списка.

После этого он будет работать только в том случае, если ссылки на странице являются абсолютными путями. Если они относительны, вам нужно построить абсолютный путь.

Смежные вопросы