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