Как я могу получить ссылки веб-страницы и скопировать URL-адрес ссылок с помощью Python?
получать ссылки с веб-страницы с помощью python и BeautifulSoup
Ответы (15)
Вот короткий фрагмент с использованием класса SoupStrainer в BeautifulSoup:
import httplib2
from bs4 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 на самом деле неплохая и охватывает ряд типичных сценариев:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/ а>
Изменить: обратите внимание, что я использовал класс SoupStrainer, потому что он немного более эффективен (с точки зрения памяти и скорости), если вы заранее знаете, что анализируете.
/usr/local/lib/python2.7/site-packages/bs4/__init__.py:128: UserWarning: The "parseOnlyThese" argument to the BeautifulSoup constructor has been renamed to "parse_only."
- person BenDundee; 19.02.2013
has_attr
. Вместо этого я вижу, что есть что-то под названием has_key
, и это работает.
- person ; 27.10.2013
hasattr
, встроенный Python: hasattr(link, "href")
- person cat; 25.03.2016
Для полноты картины, версия BeautifulSoup 4, также использующая кодировку, предоставленную сервером:
from bs4 import BeautifulSoup
import urllib.request
parser = 'html.parser' # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib.request.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().get_param('charset'))
for link in soup.find_all('a', href=True):
print(link['href'])
или версия Python 2:
from bs4 import BeautifulSoup
import urllib2
parser = 'html.parser' # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib2.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().getparam('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
parser = 'html.parser' # or 'lxml' (preferred) or 'html5lib', if installed
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, parser, from_encoding=encoding)
for link in soup.find_all('a', href=True):
print(link['href'])
Вызов soup.find_all('a', href=True)
находит все <a>
элементы, имеющие атрибут href
; элементы без атрибута пропускаются.
BeautifulSoup 3 остановил разработку в марте 2012 года; в новых проектах действительно всегда следует использовать BeautifulSoup 4.
Обратите внимание, что вам следует оставить декодирование HTML с байтов на BeautifulSoup. Вы можете сообщить BeautifulSoup о наборе символов, найденном в заголовках ответа HTTP, чтобы помочь в декодировании, но это может быть неправильным и противоречить информации заголовка <meta>
, находящейся в самом HTML, поэтому в приведенном выше примере используется Метод внутреннего класса BeautifulSoup EncodingDetector.find_declared_encoding()
, чтобы убедиться, что такие встроенные подсказки кодирования преобладают над неправильно настроенным сервером.
С requests
атрибут response.encoding
по умолчанию имеет значение Latin-1, если ответ имеет text/*
mimetype, даже если набор символов не был возвращен. Это согласуется с HTTP RFC, но болезненно при использовании с синтаксическим анализом HTML, поэтому вам следует игнорировать этот атрибут, если в заголовке Content-Type не задано значение charset
.
SoupStrainer
ты имеешь в виду? Он никуда не делся, он все еще является частью проекта.
- person Martijn Pieters; 02.02.2017
Другие рекомендовали BeautifulSoup, но гораздо лучше использовать lxml. Несмотря на свое название, он также предназначен для синтаксического анализа HTML. Он намного, намного быстрее, чем BeautifulSoup, и даже обрабатывает «сломанный» HTML лучше, чем BeautifulSoup (их претензия на известность). У него также есть API совместимости для BeautifulSoup, если вы не хотите изучать lxml API.
Больше нет причин использовать 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
lxml
в качестве анализатора по умолчанию, если он установлен.
- person Martijn Pieters; 28.12.2014
Следующий код предназначен для получения всех ссылок, доступных на веб-странице, с использованием 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]
В составлении списка "if '//' и 'url.com' not in x" - это простой способ очистить список URL-адресов «внутренних» навигационных URL-адресов сайтов и т. Д.
Ссылки могут быть в пределах множества атрибутов, поэтому вы можете передать список этих атрибутов для выбора
например, с атрибутом src и href (здесь я использую оператор, начинающийся с ^, чтобы указать, что любое из этих значений атрибутов начинается с http. Вы можете настроить это по мере необходимости
from bs4 import BeautifulSoup as bs
import requests
r = requests.get('https://stackoverflow.com/')
soup = bs(r.content, 'lxml')
links = [item['href'] if item.get('href') is not None else item['src'] for item in soup.select('[href^="http"], [src^="http"]') ]
print(links)
[attr ^ = значение]
Представляет элементы с именем атрибута attr, значение которого предваряется (предваряется) значением.
просто для получения ссылок, без B.soup и регулярного выражения:
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.
<a
и href
? Скажите rel="nofollow"
или onclick="..."
или даже просто новую строку? stackoverflow.com/questions/1732348/
- person dimo414; 13.09.2012
Этот скрипт делает то, что вы ищете, но также преобразует относительные ссылки в абсолютные.
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
Чтобы найти все ссылки, в этом примере мы будем использовать модуль urllib2 вместе с re.module *. Одна из самых мощных функций в модуле re - "re. найти все()". В то время как re.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
Почему бы не использовать регулярные выражения:
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]))
(r"<a.*?\s*href=\"(.*?)\".*?>(.*?)</a>", page)
? Благодарность!
- person user1063287; 06.04.2013
Вот пример использования принятого ответа @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)
Я нашел ответ от @ 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.
Собственный синтаксический анализатор 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"
lxml
может обрабатывать только действительный ввод, как он может заменить BeautifulSoup
?
- person alexis; 11.06.2016
lxml.html
немного снисходительнее, чем lxml.etree
. Если ваш ввод неверно сформирован, вы можете явно установить парсер BeautifulSoup: lxml.de/elementsoup.html а>. А если вы выберете BeatifulSoup, то BS3 - лучший выбор.
- person ccpizza; 11.06.2016
Может быть много повторяющихся ссылок вместе как с внешними, так и с внутренними ссылками. Чтобы различать их и просто получить уникальные ссылки с помощью наборов:
# Python 3.
import urllib
from bs4 import BeautifulSoup
url = "http://www.espncricinfo.com/"
resp = urllib.request.urlopen(url)
# Get server encoding per recommendation of Martijn Pieters.
soup = BeautifulSoup(resp, from_encoding=resp.info().get_param('charset'))
external_links = set()
internal_links = set()
for line in soup.find_all('a'):
link = line.get('href')
if not link:
continue
if link.startswith('http'):
external_links.add(link)
else:
internal_links.add(link)
# Depending on usage, full internal links may be preferred.
full_internal_links = {
urllib.parse.urljoin(url, internal_link)
for internal_link in internal_links
}
# Print all unique external and full internal links.
for link in external_links.union(full_internal_links):
print(link)
/info-service/downloads/#unserekataloge'
. Нет возможности получить полную доступную ссылку? а не только часть дополнительной ссылки? Я хочу получить ссылки на все PDF-файлы, доступные на сайте @MujeebIshaque - person x89   schedule 01.07.2021