Как я могу получить ссылки веб-страницы и скопировать URL-адрес ссылок с помощью Python?
144
Как я могу получить ссылки веб-страницы и скопировать URL-адрес ссылок с помощью Python?
Вот короткий фрагмент с использованием класса 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."
has_attr
. Вместо этого я вижу, что что-то называется,has_key
и это работает.Для полноты картины, версия 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, даже если CharacterSet не был возвращен. Это согласуется с HTTP RFC, но болезненно при использовании с синтаксическим анализом HTML, поэтому вам следует игнорировать этот атрибут, еслиcharset
в заголовке Content-Type не задано значение no .источник
SoupStrainer
ты имеешь в виду? Это никуда не делось, это все еще часть проекта .Другие рекомендовали 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
в качестве анализатора по умолчанию, если он установлен.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]
В составлении списка "if '//' и 'url.com' not in x" - это простой метод очистки списка URL-адресов «внутренних» навигационных URL-адресов сайтов и т. Д.
источник
просто для получения ссылок, без 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/…Этот скрипт делает то, что вы ищете, но также преобразует относительные ссылки в абсолютные ссылки.
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.findall ()». В то время как 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)
означает? Благодарность!Ссылки могут быть в пределах множества атрибутов, поэтому вы можете передать список этих атрибутов для выбора
например, с атрибутом 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)
Атрибут = селекторы значений
источник
Вот пример использования @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
Использование следующее:
источник
lxml
может обрабатывать только действительный ввод, как его заменитьBeautifulSoup
?lxml.html
, это немного мягче, чемlxml.etree
. Если ваш ввод неверно сформирован, вы можете явно установить парсер BeautifulSoup: lxml.de/elementsoup.html . А если вы выберете BeatifulSoup, то BS3 - лучший выбор.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']
источник
Может быть много повторяющихся ссылок, как внешних, так и внутренних. Чтобы различать их и просто получить уникальные ссылки с помощью наборов:
# 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)
источник