Получение значения атрибутов href во всех тегах <a>в html-файле с помощью Python - PullRequest
1 голос
/ 22 марта 2009

Я создаю приложение на python, и мне нужно получить URL всех ссылок на одной веб-странице. У меня уже есть функция, которая использует urllib для загрузки html-файла из Интернета и преобразования его в список строк с помощью readlines ().

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

for line in lines:
    result = re.match ('/href="(.*)"/iU', line)
    print result

Это не работает, так как выводит «None» только для каждой строки в файле, но я уверен, что по крайней мере есть 3 ссылки на открываемый файл.

Может кто-нибудь дать мне подсказку по этому поводу?

Заранее спасибо

Ответы [ 7 ]

11 голосов
/ 22 марта 2009

Красивый суп может сделать это почти тривиально:

from BeautifulSoup import BeautifulSoup as soup

html = soup('<body><a href="123">qwe</a><a href="456">asd</a></body>')
print [tag.attrMap['href'] for tag in html.findAll('a', {'href': True})]
8 голосов
/ 22 марта 2009

Другой альтернативой BeautifulSoup является lxml (http://lxml.de/);

import lxml.html
links = lxml.html.parse("http://stackoverflow.com/").xpath("//a/@href")
for link in links:
    print link
4 голосов
/ 22 марта 2009

В Python есть стандартный HTML-анализатор. Оформить заказ htmllib.

3 голосов
/ 23 марта 2009

Как уже упоминалось ранее: регулярное выражение не имеет возможности для анализа HTML. Не используйте регулярные выражения для анализа HTML. Не пропустите Go. Не собирайте £ 200.

Использовать анализатор HTML.

Но для полноты основная проблема:

re.match ('/href="(.*)"/iU', line)

Вы не используете синтаксис «/.../flags» для украшения регулярных выражений в Python. Вместо этого поместите флаги в отдельный аргумент:

re.match('href="(.*)"', line, re.I|re.U)

Другая проблема - это жадный шаблон «. *». Если у вас в строке два hrefs, он с радостью поглотит весь контент между открытием «первого матча» и закрытием »второго матча. Вы можете использовать не жадный ‘. *?’ Или, проще, ‘[^"] * ’, чтобы соответствовать только первой закрывающей кавычке.

Но не используйте регулярные выражения для анализа HTML. На самом деле.

3 голосов
/ 22 марта 2009

То, что другие не сказали вам, это то, что использование регулярных выражений для этого не является надежным решением.
Использование регулярного выражения даст вам неправильные результаты во многих ситуациях: если есть закомментированные теги , или если на странице есть текст, содержащий строку "href =", или если есть элементы

Для этого вам понадобится XPath , который является языком запросов для деревьев DOM, т.е. он позволяет вам получить любой набор узлов, удовлетворяющих заданным вами условиям (атрибуты HTML являются узлами в DOM).
XPath является хорошо стандартизированным языком в наши дни ( W3C ) и хорошо поддерживается всеми основными языками. Я настоятельно рекомендую вам использовать XPath, а не регулярное выражение для этого.
Ответ adw показывает один пример использования XPath для вашего конкретного случая.

1 голос
/ 23 марта 2009

Ну, просто для полноты я добавлю здесь то, что я нашел лучшим ответом, и я нашел это в книге «Погружение в Питон» Марка Пилигрима.

Ниже приведен код для перечисления всех URL-адресов с веб-страницы:

from sgmllib import SGMLParser

class URLLister(SGMLParser):
    def reset(self):                              
        SGMLParser.reset(self)
        self.urls = []

    def start_a(self, attrs):                     
        href = [v for k, v in attrs if k=='href']  
        if href:
            self.urls.extend(href)

import urllib, urllister
usock = urllib.urlopen("http://diveintopython.net/")
parser = urllister.URLLister()
parser.feed(usock.read())         
usock.close()      
parser.close()                    
for url in parser.urls: print url

Спасибо за все ответы.

1 голос
/ 22 марта 2009

Не делите HTML-контент на строки, так как в одной строке может быть несколько совпадений. Также не думайте, что вокруг URL всегда есть кавычки.

Сделайте что-то вроде этого:

links = re.finditer(' href="?([^\s^"]+)', content)

for link in links:
  print link
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...