Вопрос по python – получить ссылки с веб-страницы, используя python и BeautifulSoup
что вы ищете, но также разрешает относительные ссылки на абсолютные ссылки.
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
lSoup:
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.htm
Редактировать: обратите внимание, что я использовал класс 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."
has_attr
. Вместо этого я вижу что-то под названиемhas_key
и это работает.
версия 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'])
Thesoup.find_all('a', href=True)
вызов находит все<a>
элементы, которые имеютhref
атрибут; элементы без атрибута пропускаются.
BeautifulSoup 3 прекратил разработку в марте 2012 года; новые проекты действительно должны использовать BeautifulSoup 4, всегда.
Обратите внимание, что вы должны оставить декодирование HTML из байтов to BeautifulSoup. Вы можете сообщить BeautifulSoup о наборе символов, найденном в заголовках ответа HTTP, чтобы помочь в декодировании, но этоможе быть неправым и конфликтовать с<meta>
информация заголовка находится в самом HTML, поэтому в приведенном выше примере используется метод внутреннего класса BeautifulSoupEncodingDetector.find_declared_encoding()
, чтобы убедиться, что такие подсказки встроенной кодировки побеждают неправильно настроенный сервер.
Сrequests
,response.encoding
атрибут по умолчанию имеет значение Latin-1, если в ответе естьtext/*
mimetype, даже если набор символов не был возвращен. Это согласуется с HTTP RFC, но болезненно при использовании с разбором HTML, поэтому вы должны игнорировать этот атрибут, когда нетcharset
устанавливается в заголовке Content-Type.
SoupStrainer
ты имеешь в виду? Это никуда не делась, это все еще часть проекта.
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
как парсер по умолчанию, если установлен.
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'
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» не в x »- это простой метод очистки списка URL-адресов« внутренних »URL-адресов сайтов и т. Д.
Чтобы найти все ссылки, в этом примере мы будем использовать модуль urllib2 вместе с re.module * Одной из самых мощных функций в модуле re является "re.findall ()". В то время как re.search () используется для поиска первого совпадения для шаблона, re.findall () находитвс совпадений и возвращает их в виде списка строк, где каждая строка представляет одно совпадение *
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
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 вопросы / 1732348 / ...
Почему бы не использовать регулярные выражения:
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)
средства? Благодарность
Вот пример использования @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)
после следующего исправления (охватывающего сценарий, когда он не работал правильно):
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.
было бы более целесообразно использовать 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 может пригодиться.
НОТ: Прямой синтаксический анализ 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
?
lxml.html
немного мягче, чемlxml.etree
. Если ваш ввод не правильно сформирован, вы можете явно установить синтаксический анализатор BeautifulSoup: Lxml.de / elementsoup.html. И если вы используете BeatifulSoup, тогда BS3 - лучший выбор.