получение ссылок с веб-страницы с помощью python и BeautifulSoup



Как я могу получить ссылки на веб-страницу и скопировать url-адрес ссылок с помощью Python?

7174   14  

14 ответов:

вот короткий фрагмент с использованием класса SoupStrainer в BeautifulSoup:

import httplib2
from BeautifulSoup import BeautifulSoup, SoupStrainer

http = httplib2.Http()
status, response = http.request('http://www.nytimes.com')

for link in BeautifulSoup(response, parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        print link['href']

документация BeautifulSoup на самом деле довольно хороша и охватывает ряд типичных сценариев:

http://www.crummy.com/software/BeautifulSoup/documentation.html

Edit: обратите внимание, что я использовал класс SoupStrainer, потому что он немного более эффективен (память и скорость), если вы знаете, что вы анализируете заранее.

для полноты картины, версия BeautifulSoup 4, используя кодировку, предоставленную сервером, а также:

from bs4 import BeautifulSoup
import urllib2

resp = urllib2.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, from_encoding=resp.info().getparam('charset'))

for link in soup.find_all('a', href=True):
    print link['href']

или версия Python 3:

from bs4 import BeautifulSoup
import urllib.request

resp = urllib.request.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, from_encoding=resp.info().get_param('charset'))

for link in soup.find_all('a', href=True):
    print(link['href'])

и версия с использованием requests библиотека, который, как написано, будет работать как в Python 2, так и в 3:

from bs4 import BeautifulSoup
from bs4.dammit import EncodingDetector
import requests

resp = requests.get("http://www.gpsbasecamp.com/national-parks")
http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True)
encoding = html_encoding or http_encoding
soup = BeautifulSoup(resp.content, from_encoding=encoding)

for link in soup.find_all('a', href=True):
    print(link['href'])

The soup.find_all('a', href=True) призыв находит все <a> элементы, которые имеют href атрибут; элементы без атрибута являются пропущенный.

BeautifulSoup 3 остановил развитие в марте 2012; новые проекты действительно должны использовать BeautifulSoup 4, всегда.

обратите внимание, что вы должны оставить декодирование HTML из байтов to BeautifulSoup. Вы можете сообщить BeautifulSoup о наборе символов, найденном в заголовках ответов HTTP, чтобы помочь в декодировании, но это можете ошибаться и конфликтовать с <meta> информация о заголовке находится в самом HTML, поэтому выше используется BeautifulSoup внутренний метод класса EncodingDetector.find_declared_encoding() чтобы убедиться, что такие встроенные подсказки кодирования побеждают неверно настроенный сервер.

С requests на response.encoding атрибут по умолчанию латинский-1, если ответ имеет text/* mimetype, даже если набор символов не был возвращен. Это согласуется с HTTP RFC, но болезненно при использовании с синтаксическим анализом HTML, поэтому вы должны игнорировать этот атрибут, когда нет charset находится в Content-Type заголовок.

другие рекомендовали BeautifulSoup, но это гораздо лучше использовать lxml. Несмотря на свое название, он также предназначен для разбора и очистки HTML. Это намного, намного быстрее, чем BeautifulSoup, и он даже обрабатывает "сломанный" HTML лучше, чем BeautifulSoup (их претензия на славу). Он также имеет API совместимости для BeautifulSoup, если вы не хотите изучать API lxml.

Ян Бликинг соглашается.

больше нет причин использовать BeautifulSoup, если вы не находитесь на Google App Engine или что-то, где ничего не чисто Python не допускается.

lxml.HTML также поддерживает CSS3-селекторов, так что такого рода вещи является тривиальным.

пример с lxml и xpath будет выглядеть так:

import urllib
import lxml.html
connection = urllib.urlopen('http://www.nytimes.com')

dom =  lxml.html.fromstring(connection.read())

for link in dom.xpath('//a/@href'): # select the url in href for all a tags(links)
    print link
import urllib2
import BeautifulSoup

request = urllib2.Request("http://www.gpsbasecamp.com/national-parks")
response = urllib2.urlopen(request)
soup = BeautifulSoup.BeautifulSoup(response)
for a in soup.findAll('a'):
  if 'national-park' in a['href']:
    print 'found a url with national-park in the link'

следующий код должен получить все ссылки, доступные на веб-странице с помощью urllib2 и BeautifulSoup4

    import urllib2
    from bs4 import BeautifulSoup
    url = urllib2.urlopen("http://www.espncricinfo.com/").read()
    soup = BeautifulSoup(url)
    for line in soup.find_all('a'):
            print(line.get('href'))

под капотом BeautifulSoup теперь использует lxml. Запросы, lxml и список понимания делает убийцу комбо.

import requests
import lxml.html

dom = lxml.html.fromstring(requests.get('http://www.nytimes.com').content)

[x for x in dom.xpath('//a/@href') if '//' in x and 'nytimes.com' not in x]

в списке comp, "если' / / ' и 'url.com" не в x " - это простой метод очистки списка url-адресов внутренних навигационных URL-адресов сайтов и т. д.

, чтобы найти все ссылки, мы будем в этом примере использование модуля urllib2 вместе с помощью огня.модуль *Одна из самых мощных функций в модуле re-это "re.findall ()". Пока ре.search () используется для поиска первого совпадения для шаблона re.findall () находит все совпадения и возвращает их в виде списка строк, причем каждая строка представляет одно совпадение*

import urllib2

import re
#connect to a URL
website = urllib2.urlopen(url)

#read html code
html = website.read()

#use re.findall to get all the links
links = re.findall('"((http|ftp)s?://.*?)"', html)

print links

просто для получения ссылок, без B. суп и регулярное выражение:

import urllib2
url="http://www.somewhere.com"
page=urllib2.urlopen(url)
data=page.read().split("</a>")
tag="<a href=\""
endtag="\">"
for item in data:
    if "<a href" in item:
        try:
            ind = item.index(tag)
            item=item[ind+len(tag):]
            end=item.index(endtag)
        except: pass
        else:
            print item[:end]

для более сложных операций, конечно, BSoup по-прежнему предпочтительнее.

почему бы не использовать регулярные выражения:

import urllib2
import re
url = "http://www.somewhere.com"
page = urllib2.urlopen(url)
page = page.read()
links = re.findall(r"<a.*?\s*href=\"(.*?)\".*?>(.*?)</a>", page)
for link in links:
    print('href: %s, HTML text: %s' % (link[0], link[1]))

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

import urllib
import lxml.html
import urlparse

def get_dom(url):
    connection = urllib.urlopen(url)
    return lxml.html.fromstring(connection.read())

def get_links(url):
    return resolve_links((link for link in get_dom(url).xpath('//a/@href')))

def guess_root(links):
    for link in links:
        if link.startswith('http'):
            parsed_link = urlparse.urlparse(link)
            scheme = parsed_link.scheme + '://'
            netloc = parsed_link.netloc
            return scheme + netloc

def resolve_links(links):
    root = guess_root(links)
    for link in links:
        if not link.startswith('http'):
            link = urlparse.urljoin(root, link)
        yield link  

for link in get_links('http://www.google.com'):
    print link

вот пример использования @ars принятый ответ и BeautifulSoup4,requests и wget модули для обработки загрузки.

import requests
import wget
import os

from bs4 import BeautifulSoup, SoupStrainer

url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/eeg-mld/eeg_full/'
file_type = '.tar.gz'

response = requests.get(url)

for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        if file_type in link['href']:
            full_path = url + link['href']
            wget.download(full_path)

собственный парсер BeatifulSoup может быть медленным. Возможно, более целесообразно использовать lxml который способен анализировать непосредственно из URL (с некоторыми ограничениями, указанными ниже).

import lxml.html

doc = lxml.html.parse(url)

links = doc.xpath('//a[@href]')

for link in links:
    print link.attrib['href']

приведенный выше код вернет ссылки как есть, и в большинстве случаев они будут относительными ссылками или абсолютными из корня сайта. Поскольку мой вариант использования состоял только в извлечении определенного типа ссылок, ниже приведена версия, которая преобразует ссылки в полные URL-адреса и которая опционально принимает шаблон глобуса, например *.mp3. Он не будет обрабатывать одиночные и двойные точки в относительных путях, хотя, но до сих пор у меня не было необходимости в этом. Если вам нужно разобрать фрагменты URL, содержащие ../ или ./ затем urlparse.urljoin может пригодиться.

Примечание: прямой разбор url lxml не обрабатывает загрузку из https и не делает перенаправления, поэтому по этой причине версия ниже использует urllib2 + lxml.

#!/usr/bin/env python
import sys
import urllib2
import urlparse
import lxml.html
import fnmatch

try:
    import urltools as urltools
except ImportError:
    sys.stderr.write('To normalize URLs run: `pip install urltools --user`')
    urltools = None


def get_host(url):
    p = urlparse.urlparse(url)
    return "{}://{}".format(p.scheme, p.netloc)


if __name__ == '__main__':
    url = sys.argv[1]
    host = get_host(url)
    glob_patt = len(sys.argv) > 2 and sys.argv[2] or '*'

    doc = lxml.html.parse(urllib2.urlopen(url))
    links = doc.xpath('//a[@href]')

    for link in links:
        href = link.attrib['href']

        if fnmatch.fnmatch(href, glob_patt):

            if not href.startswith(('http://', 'https://' 'ftp://')):

                if href.startswith('/'):
                    href = host + href
                else:
                    parent_url = url.rsplit('/', 1)[0]
                    href = urlparse.urljoin(parent_url, href)

                    if urltools:
                        href = urltools.normalize(href)

            print href

использование выглядит следующим образом:

getlinks.py http://stackoverflow.com/a/37758066/191246
getlinks.py http://stackoverflow.com/a/37758066/191246 "*users*"
getlinks.py http://fakedomain.mu/somepage.html "*.mp3"
import urllib2
from bs4 import BeautifulSoup
a=urllib2.urlopen('http://dir.yahoo.com')
code=a.read()
soup=BeautifulSoup(code)
links=soup.findAll("a")
#To get href part alone
print links[0].attrs['href']

Я нашел ответ на @Blairg23 работает, после следующей коррекции (охватывающей сценарий, где он не смог работать правильно):

for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        if file_type in link['href']:
            full_path =urlparse.urljoin(url , link['href']) #module urlparse need to be imported
            wget.download(full_path)

Для Python 3:

urllib.parse.urljoin должен использоваться для получения полного URL-адреса вместо этого.

Comments

    Ничего не найдено.