Scrapy: хранить все внешние ссылки и сканировать все внутренние ссылки

Я работаю над парсером, который просматривает все внутренние ссылки с начального URL-адреса и собирает только внешние ссылки с scrapy. Однако моя главная проблема заключается в классификации внешних ссылок и внутренних ссылок. Например, когда я пытаюсь отфильтровать внешние ссылки с помощью link.startswith("http") or link.startswith("ftp") or link.startswith("www"), если веб-сайт ссылается на свой собственный веб-сайт с абсолютным путем (www.my-domain.com/about вместо /about), он классифицирует его как внешнюю ссылку, даже если это не так. Ниже приведен мой код:

import scrapy
from lab_relationship.items import Links

class WebSpider(scrapy.Spider):
    name = "web"
    allowed_domains = ["my-domain.com"]
    start_urls = (
        'www.my-domain.com',
    )

    def parse(self, response):
        """ finds all external links"""
        items = []
        for link in set(response.xpath('//a/@href').extract()):
            item = Links()
            if len(link) > 1:
                if link.startswith("/") or link.startswith("."):
                    # internal link
                    url = response.urljoin(link)
                    item['internal'] = url
                    #yield scrapy.Request(url, self.parse)
                elif link.startswith("http") or link.startswith("ftp") or link.startswith("www"):
                    # external link
                    item['external'] = link
                else:
                    # misc. links: mailto, id (#)
                    item['misc'] = link
                items.append(item)
        return items

Какие-либо предложения?


person THIS USER NEEDS HELP    schedule 03.10.2015    source источник


Ответы (2)


Используйте извлекатель ссылок.

При создании экземпляра вы должны передать разрешенный домен. Вам не нужно беспокоиться об указании необходимых тегов, так как (согласно документам) параметр tags принимает ('a', 'area') по умолчанию.

На примере веб-сайта Rust lang код для печати всех внутренних ссылок с их домена будет выглядеть так:

import scrapy
from scrapy.linkextractors import LinkExtractor


class RustSpider(scrapy.Spider):
    name = "rust"
    allowed_domains = ["www.rust-lang.org"]
    start_urls = (
        'http://www.rust-lang.org/',
    )

    def parse(self, response):
        extractor = LinkExtractor(allow_domains='rust-lang.org')
        links = extractor.extract_links(response)
        for link in links:
            print link.url

и результатом будет список таких ссылок: https://doc.rust-lang.org/nightly/reference.html (больше не могу публиковать), исключив при этом все ссылки на StackOverflow.

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

person Jakub    schedule 03.10.2015
comment
Хм.. вы предлагаете сделать набор внутренних ссылок с помощью LinkExtractor, и для всех ссылок проверить, совпадают ли они с внутренними ссылками, и если нет, то это внешние ссылки? - person THIS USER NEEDS HELP; 03.10.2015
comment
Не совсем так, установив deny_domains='domain' можно извлекать ссылки не в данном домене (внешние). - person Jakub; 03.10.2015

Оператор if может принимать несколько операторов or, а не только два.

person kcrk    schedule 03.10.2015
comment
Но мой массив также будет включать внутренние ссылки. Мне нужны только внешние ссылки - person THIS USER NEEDS HELP; 03.10.2015
comment
Да, только что заметил. Глядя на ваш код, строка if link.startswith(/) или link.startswith(.): может иметь несколько операторов or, в противном случае может использоваться переключатель - person kcrk; 03.10.2015
comment
Я уже использую несколько or в своем коде, и я не понимаю, как это будет отфильтровывать абсолютные ссылки из относительных ссылок. - person THIS USER NEEDS HELP; 03.10.2015
comment
вы знаете свой внутренний домен, так что если ссылка начинается с внутреннего домена, то дополнительный if должен подцепить любой внутренний домен? то есть: link.startswith("http://www.my-domain.com/") - person kcrk; 03.10.2015
comment
Основная проблема заключается в том, что с помощью условных операторов классифицируйте www.my-domain.com как по внешним, так и по внутренним ссылкам, когда он должен быть внутренним. Если бы это был, скажем, www.other-domain.com, то его следовало бы классифицировать как внешний. - person THIS USER NEEDS HELP; 03.10.2015
comment
Ах, извините. Продолжаю отвечать на старый комментарий. Я думал об этом, но такой домен, как blog.my-domain.com, все равно должен соответствовать внутренней ссылке, не так ли? - person THIS USER NEEDS HELP; 03.10.2015
comment
отсюда мое предложение оператора switch, поскольку, как только он соответствует, вы запускаете свой код и ломаетесь. вы могли бы просто обрабатывать все, что не соответствует, как провал - person kcrk; 03.10.2015
comment
Если мы просто попытаемся сопоставить подстроку исходного домена, то даже что-то вроде facebook.com/my-domain.com потерпит неудачу. - person THIS USER NEEDS HELP; 03.10.2015
comment
Для этого лучше использовать регулярное выражение. - person kcrk; 03.10.2015