Веб-майнинг, парсинг или сканирование? Какой инструмент/библиотеку следует использовать?

Я хочу просканировать и сохранить некоторые веб-страницы в формате HTML. Скажем, зайдите на сотни популярных веб-сайтов и просто сохраните их главные страницы и страницы «О нас».

Я изучил множество вопросов, но не нашел ответа на этот вопрос ни при сканировании веб-сайтов, ни при очистке веб-страниц.

Какую библиотеку или инструмент следует использовать для создания решения? Или есть даже какие-то существующие инструменты, которые могут справиться с этим?


person Flake    schedule 11.10.2011    source источник
comment
Как вы идентифицируете страницы «О нас»?   -  person    schedule 11.10.2011
comment
Скажем, просто сопоставьте регулярное выражение в URL для about. Если совпадают, сохраните, если нет, просто оставьте. Нет проблем с ложноотрицательным результатом.   -  person Flake    schedule 11.10.2011
comment
@Flake, чтобы быть в безопасности, URL-адреса с о в тексте и внутренние ссылки. Конечно, у кого-то могут быть просто ссылки, такие как информация о компании, без слов о ней.   -  person Ali    schedule 11.10.2011


Ответы (6)


Здесь действительно нет хорошего решения. Вы правы, поскольку подозреваете, что Python, вероятно, лучший способ начать, потому что он невероятно сильно поддерживает регулярные выражения.

Чтобы реализовать что-то подобное, помогут глубокие знания SEO (поисковая оптимизация), поскольку эффективная оптимизация веб-страницы для поисковых систем говорит вам о том, как ведут себя поисковые системы. Я бы начал с такого сайта, как SEOMoz.

Что касается идентификации страницы «о нас», у вас есть только 2 варианта:

а) Для каждой страницы получите ссылку на страницу о нас и передайте ее своему сканеру.

б) Проанализируйте все ссылки страницы на наличие определенных ключевых слов, таких как "о нас", "о нас", "узнать больше" и т. д.

при использовании варианта b будьте осторожны, так как вы можете застрять в бесконечном цикле, поскольку веб-сайт будет ссылаться на одну и ту же страницу много раз, особенно если ссылка находится в верхнем или нижнем колонтитуле, страница может ссылаться даже на себя. Чтобы избежать этого, вам нужно создать список посещенных ссылок и следить за тем, чтобы они не посещались повторно.

Наконец, я бы порекомендовал, чтобы ваш поисковый робот соблюдал инструкции в файле robot.txt, и, вероятно, было бы неплохо не переходить по ссылкам, отмеченным rel="nofollow", поскольку они в основном используются для внешних ссылок. Опять же, узнайте это и многое другое, читая о SEO.

С уважением,

person Ali    schedule 11.10.2011

При переходе на Python вас могут заинтересовать механизировать и BeautifulSoup.

Mechanize как бы имитирует браузер (включая параметры проксирования, подделки идентификаторов браузера, перенаправления страниц и т. д.) и позволяет легко извлекать формы, ссылки и т. д. Однако документация немного грубая/разреженная.

Некоторый пример кода (с веб-сайта mechanize), чтобы дать вам представление:

import mechanize
br = mechanize.Browser()
br.open("http://www.example.com/")
# follow second link with element text matching regular expression
html_response = br.follow_link(text_regex=r"cheese\s*shop", nr=1)
print br.title()
print  html_response

BeautifulSoup позволяет довольно легко анализировать html-контент (который вы могли бы получить с помощью mechanize) и поддерживает регулярные выражения.

Некоторый пример кода:

from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup(html_response)

rows = soup.findAll('tr')
for r in rows[2:]:  #ignore first two rows
    cols = r.findAll('td')
    print cols[0].renderContents().strip()    #print content of first column

Итак, эти 10 строк выше в значительной степени готовы к копированию и вставке для печати содержимого первого столбца каждой строки таблицы на веб-сайте.

person Rabarberski    schedule 11.10.2011

Попробуйте scrapy. Это библиотека веб-скрейпинга для Python. Если ожидается простой python-скрипт, попробуйте urllib2 на python.

person jvc    schedule 11.10.2011

Python ==> Curl ‹-- лучшая реализация сканера

Следующий код может просканировать 10 000 страниц за 300 секунд на хорошем сервере.

#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
# $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $

#
# Usage: python retriever-multi.py <file with URLs to fetch> [<# of
#          concurrent connections>]
#

import sys
import pycurl

# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
    import signal
    from signal import SIGPIPE, SIG_IGN
    signal.signal(signal.SIGPIPE, signal.SIG_IGN)
except ImportError:
    pass


# Get args
num_conn = 10
try:
    if sys.argv[1] == "-":
        urls = sys.stdin.readlines()
    else:
        urls = open(sys.argv[1]).readlines()
    if len(sys.argv) >= 3:
        num_conn = int(sys.argv[2])
except:
    print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
    raise SystemExit


# Make a queue with (url, filename) tuples
queue = []
for url in urls:
    url = url.strip()
    if not url or url[0] == "#":
        continue
    filename = "doc_%03d.dat" % (len(queue) + 1)
    queue.append((url, filename))


# Check args
assert queue, "no URLs given"
num_urls = len(queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"


# Pre-allocate a list of curl objects
m = pycurl.CurlMulti()
m.handles = []
for i in range(num_conn):
    c = pycurl.Curl()
    c.fp = None
    c.setopt(pycurl.FOLLOWLOCATION, 1)
    c.setopt(pycurl.MAXREDIRS, 5)
    c.setopt(pycurl.CONNECTTIMEOUT, 30)
    c.setopt(pycurl.TIMEOUT, 300)
    c.setopt(pycurl.NOSIGNAL, 1)
    m.handles.append(c)


# Main loop
freelist = m.handles[:]
num_processed = 0
while num_processed < num_urls:
    # If there is an url to process and a free curl object, add to multi stack
    while queue and freelist:
        url, filename = queue.pop(0)
        c = freelist.pop()
        c.fp = open(filename, "wb")
        c.setopt(pycurl.URL, url)
        c.setopt(pycurl.WRITEDATA, c.fp)
        m.add_handle(c)
        # store some info
        c.filename = filename
        c.url = url
    # Run the internal curl state machine for the multi stack
    while 1:
        ret, num_handles = m.perform()
        if ret != pycurl.E_CALL_MULTI_PERFORM:
            break
    # Check for curl objects which have terminated, and add them to the freelist
    while 1:
        num_q, ok_list, err_list = m.info_read()
        for c in ok_list:
            c.fp.close()
            c.fp = None
            m.remove_handle(c)
            print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
            freelist.append(c)
        for c, errno, errmsg in err_list:
            c.fp.close()
            c.fp = None
            m.remove_handle(c)
            print "Failed: ", c.filename, c.url, errno, errmsg
            freelist.append(c)
        num_processed = num_processed + len(ok_list) + len(err_list)
        if num_q == 0:
            break
    # Currently no more I/O is pending, could do something in the meantime
    # (display a progress bar, etc.).
    # We just call select() to sleep until some more data is available.
    m.select(1.0)


# Cleanup
for c in m.handles:
    if c.fp is not None:
        c.fp.close()
        c.fp = None
    c.close()
m.close()
person codersofthedark    schedule 29.11.2011

Если вы собираетесь создать сканер, вам необходимо (для Java):

  1. Узнайте, как использовать классы java.net.URL и java.net.URLConnection или библиотеку HttpClient.
  2. Понимание заголовков HTTP-запроса/ответа
  3. Понимать перенаправления (как HTTP, HTML и Javascript)
  4. Разбираться в кодировках контента (кодировках)
  5. Используйте хорошую библиотеку для разбора плохо сформированного HTML (например, cyberNecko, Jericho, JSoup).
  6. Делайте одновременные HTTP-запросы к разным хостам, но убедитесь, что вы отправляете не более одного запроса на один и тот же хост каждые ~ 5 секунд.
  7. Сохраняйте загруженные страницы, поэтому вам не нужно обновлять их каждый день, если они не меняются так часто (HBase может быть полезен).
  8. Способ извлечения ссылок с текущей страницы для сканирования следующей
  9. Соблюдать robots.txt

Куча других вещей тоже.

Это не так сложно, но есть много неудобных крайних случаев (например, перенаправления, обнаружение кодировки (оформить заказ Tika)).

Для более базовых требований вы можете использовать wget. Heretrix — еще один вариант, но еще один фреймворк для изучения.

Идентифицировать страницы «О нас» можно с помощью различных эвристик:

  1. текст входящей ссылки
  2. Заголовок страницы
  3. контент на странице
  4. URL-адрес

если вы хотите быть более количественным, вы можете использовать машинное обучение и классификатор (возможно, байесовский).

Сохранить главную страницу, очевидно, проще, но перенаправления главной страницы (иногда на разные домены и часто реализованные в мета-теге перенаправления HTML или даже в JS) очень распространены, поэтому вам нужно справиться с этим.

person Joel    schedule 11.10.2011
comment
Привет Джоэл, спасибо за ваш интересный ответ. Не могли бы вы связаться со мной через мой профиль, чтобы поговорить подробнее о поисковом роботе, мне было бы интересно поговорить с вами более подробно (и в конечном итоге нанять вас, если вы заинтересованы). Спасибо :) - person Cyril N.; 08.03.2017

Heritrix немного сложно освоить, но его можно настроить таким образом, чтобы отображалась только домашняя страница и страница, которая «выглядит» (с использованием фильтра регулярных выражений), будет просканирована.

Дополнительные сканеры Java (веб) с открытым исходным кодом: http://java-source.net/open-source/crawlers

person Bart Kiers    schedule 11.10.2011