2014-12-19 3 views
0

Привет, ребята и девочки,XPath/Scrapy scrape DOCTYPE

Я строю скребок с помощью Scrapy и XPath. То, что меня интересует соскабливанием, - это DOCTYPE со всех сайтов, которые я пересекаю, и мне трудно найти документацию по этому поводу, и я чувствую, что это должно быть возможно, учитывая, что это относительно простой запрос. Какие-либо предложения?

Cheers,

Joey

Вот код, который я до сих пор:

import scrapy 
from scrapy.selector import HtmlXPathSelector 
from scrapy.http import HtmlResponse 
from tutorial.items import DanishItem 
from scrapy.http import Request 
import csv 


class DanishSpider(scrapy.Spider): 
    name = "dmoz" 
    allowed_domains = [] 
    start_urls = [very long list of websites] 

    def parse(self, response): 
    for sel in response.xpath(???): 
     item = DanishItem() 
     item['website'] = response 
     item['DOCTYPE'] = sel.xpath('????').extract() 
     yield item 

Новый паук, извлекает DOCTYPE, но по какой-то причине будет печатать мой ответ на указанный .json файл 15 раз, а не только один раз

class DanishSpider(scrapy.Spider): 
    name = "dmoz" 
    allowed_domains = [] 
    start_urls = ["http://wwww.example.com"] 

    def parse(self, response): 
    for sel in response.selector._root.getroottree().docinfo.doctype: 
     el = response.selector._root.getroottree().docinfo.doctype 
     item = DanishItem() 
     item['website'] = response 
     item['doctype'] = el 
     yield item 

ответ

1

С scrapy использует lxml в качестве селектора по умолчанию, вы можете использовать response.selector ручку, чтобы получить эту информацию от lxml, как это:

response.selector._root.getroottree().docinfo.doctype 

Этого должно быть достаточно, но если бы вы другой подход, читайте дальше.

Вы должны быть в состоянии извлечь ту же информацию, используя scrapy «сек регулярок экстрактор:

response.selector.re("<!\s*DOCTYPE\s*(.*?)>") 

, но, к сожалению, это не будет работать из-за того, что lxml имеет довольно сомнительное поведение (a bug ?) сбрасывания информации doctype при сериализации. Вот почему вы не можете получить его непосредственно с selector.re.
Вы можете преодолеть это маленькое препятствие достаточно просто путем использования re модуля непосредственно на response.body текст, который должным образом сериализованная:

import re 
s = re.search("<!\s*doctype\s*(.*?)>", response.body, re.IGNORECASE) 
doctype = s.group(1) if s else "" 

Update:

Что касается другого вопроса, причина следующие. Линия:

response.selector._root.getroottree().docinfo.doctype 

Вернуть string, а не список или аналогичный итератор. Таким образом, когда вы повторяете его, вы в основном повторяете буквы в этой строке. Если, например, ваш DOCTYPE равен <!DOCTYPE html>, в этой строке содержится 15 символов, и поэтому ваш цикл повторяется 15 раз. Вы можете это сделать так:

for sel in response.selector._root.getroottree().docinfo.doctype: 
    print sel 

и вы должны получить строку DOCTYPE, напечатанную на одну строку.

Что нужно сделать, так это просто удалить петлю for и просто получить данные без зацикливания. Кроме того, если по item['website'] = response вы намерены собирать URL-адрес веб-сайта, вы должны изменить его на: item['website'] = response.url. Таким образом, в основном это:

def parse(self, response): 
    doctype = response.selector._root.getroottree().docinfo.doctype 
    item = DanishItem() 
    item['website'] = response.url 
    item['doctype'] = doctype 
    yield item 
+0

Это отлично работает!Единственное, что я сейчас не могу понять, это то, почему я получаю ответ, написанный в моем .json-файле 15 раз, а не только один раз, см. Выше. Edit –

+0

Проверьте мое обновление в ответе. – bosnjak

+0

Благодарим вас за подробное объяснение! Это отлично работает :) –