Antworten:
Hier ist ein kurzer Ausschnitt aus der SoupStrainer-Klasse in 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'])
Die BeautifulSoup-Dokumentation ist eigentlich recht gut und deckt eine Reihe typischer Szenarien ab:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/
Bearbeiten: Beachten Sie, dass ich die SoupStrainer-Klasse verwendet habe, weil sie etwas effizienter ist (Speicher und Geschwindigkeit), wenn Sie im Voraus wissen, was Sie analysieren.
/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
. Stattdessen sehe ich, dass es etwas gibt, das heißt has_key
und es funktioniert.
Der Vollständigkeit halber die BeautifulSoup 4-Version, die auch die vom Server bereitgestellte Codierung verwendet:
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'])
oder die Python 2-Version:
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']
und eine Version mit der requests
Bibliothek , die wie geschrieben sowohl in Python 2 als auch in Python 3 funktioniert:
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'])
Der soup.find_all('a', href=True)
Aufruf findet alle <a>
Elemente, die ein href
Attribut haben. Elemente ohne das Attribut werden übersprungen.
BeautifulSoup 3 hat die Entwicklung im März 2012 eingestellt. Neue Projekte sollten wirklich immer BeautifulSoup 4 verwenden.
Beachten Sie, dass Sie den HTML-Code von Bytes in BeautifulSoup dekodieren sollten . Sie können BeautifulSoup über den Zeichensatz informieren, der in den HTTP-Antwortheadern enthalten ist, um die Dekodierung zu unterstützen. Dies kann jedoch falsch sein und mit <meta>
den im HTML selbst enthaltenen Headerinformationen in Konflikt stehen. Aus diesem Grund wird die interne Klassenmethode BeautifulSoup verwendet EncodingDetector.find_declared_encoding()
, um dies sicherzustellen Solche eingebetteten Codierungshinweise überzeugen einen falsch konfigurierten Server.
Bei requests
ist das response.encoding
Attribut standardmäßig Latin-1, wenn die Antwort einen text/*
Mimetyp hat, auch wenn kein Zeichensatz zurückgegeben wurde. Dies stimmt mit den HTTP-RFCs überein, ist jedoch bei der HTML-Analyse schmerzhaft. Daher sollten Sie dieses Attribut ignorieren, wenn charset
im Content-Type-Header no festgelegt ist.
SoupStrainer
meinst du? Es ging nirgendwo hin, es ist immer noch Teil des Projekts .
Andere haben BeautifulSoup empfohlen, aber es ist viel besser, lxml zu verwenden . Trotz seines Namens dient es auch zum Parsen und Scraping von HTML. Es ist viel, viel schneller als BeautifulSoup und es handhabt sogar "kaputtes" HTML besser als BeautifulSoup (ihr Anspruch auf Ruhm). Es hat auch eine Kompatibilitäts-API für BeautifulSoup, wenn Sie die lxml-API nicht lernen möchten.
Es gibt keinen Grund mehr, BeautifulSoup zu verwenden, es sei denn, Sie verwenden Google App Engine oder etwas, bei dem etwas, das nicht nur Python ist, nicht zulässig ist.
lxml.html unterstützt auch CSS3-Selektoren, so dass solche Dinge trivial sind.
Ein Beispiel mit lxml und xpath würde folgendermaßen aussehen:
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
bei Installation als Standardparser verwendet.
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'
Der folgende Code dient zum Abrufen aller auf einer Webseite verfügbaren Links mit urllib2
und 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'))
Unter der Haube verwendet BeautifulSoup jetzt lxml. Anfragen, lxml & Listenverständnis machen eine Killer-Combo.
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]
In der Liste comp ist das "if '//' und 'url.com' not in x" eine einfache Methode, um die URL-Liste der 'internen' Navigations-URLs der Websites usw. zu bereinigen.
Nur um die Links zu erhalten, ohne B.soup und Regex:
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]
Für komplexere Operationen wird BSoup natürlich immer noch bevorzugt.
<a
und href
? Sagen Sie rel="nofollow"
oder onclick="..."
oder nur eine neue Zeile? stackoverflow.com/questions/1732348/…
Dieses Skript macht das, wonach Sie suchen, löst aber auch die relativen Links zu absoluten Links auf.
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
Um alle Links zu finden, verwenden wir in diesem Beispiel das Modul urllib2 zusammen mit dem Modul re.module. * Eine der leistungsstärksten Funktionen im Modul re ist "re.findall ()". Während re.search () verwendet wird, um die erste Übereinstimmung für ein Muster zu finden, findet re.findall () alle Übereinstimmungen und gibt sie als Liste von Zeichenfolgen zurück, wobei jede Zeichenfolge eine Übereinstimmung darstellt *
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
Warum nicht reguläre Ausdrücke verwenden:
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)
bedeutet? Vielen Dank!
Links können sich innerhalb einer Vielzahl von Attributen befinden, sodass Sie eine Liste dieser Attribute zur Auswahl übergeben können
Zum Beispiel mit den Attributen src und href (hier verwende ich den Operator begin with ^, um anzugeben, dass einer dieser Attributwerte mit http beginnt. Sie können dies nach Bedarf anpassen
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 ^ = Wert]
Stellt Elemente mit dem Attributnamen attr dar, dessen Wert vor dem Wert steht.
Hier ist ein Beispiel @ars akzeptierte Antwort mit und BeautifulSoup4
, requests
und wget
Module die Downloads zu handhaben .
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)
Ich fand die Antwort von @ Blairg23 nach der folgenden Korrektur (die das Szenario abdeckt, in dem es nicht richtig funktioniert hat):
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)
Für Python 3:
urllib.parse.urljoin
muss verwendet werden, um stattdessen die vollständige URL zu erhalten.
Der Parser von BeatifulSoup kann langsam sein. Es ist möglicherweise praktikabler, lxml zu verwenden, das direkt von einer URL aus analysiert werden kann (mit einigen unten genannten Einschränkungen).
import lxml.html
doc = lxml.html.parse(url)
links = doc.xpath('//a[@href]')
for link in links:
print link.attrib['href']
Der obige Code gibt die Links so zurück, wie sie sind, und in den meisten Fällen handelt es sich um relative oder absolute Links vom Site-Stammverzeichnis. Da mein Anwendungsfall darin bestand, nur eine bestimmte Art von Links zu extrahieren, finden Sie unten eine Version, die die Links in vollständige URLs konvertiert und optional ein Glob-Muster wie akzeptiert *.mp3
. Es werden zwar keine einfachen und doppelten Punkte in den relativen Pfaden verarbeitet, aber bisher hatte ich keine Notwendigkeit dafür. Wenn Sie zu parsen URL - Fragmente enthalten ../
oder ./
dann urlparse.urljoin könnte sich als nützlich.
HINWEIS : Das direkte Parsen von lxml-URLs übernimmt nicht das Laden von https
und leitet keine Weiterleitungen durch. Aus diesem Grund verwendet die folgende Version 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
Die Verwendung ist wie folgt:
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
kann nur gültige Eingaben verarbeiten, wie kann es ersetzen BeautifulSoup
?
lxml.html
ist ein bisschen nachsichtiger als die lxml.etree
. Wenn Ihre Eingabe nicht korrekt ist, können Sie den BeautifulSoup-Parser explizit festlegen: lxml.de/elementsoup.html . Und wenn Sie sich für BeatifulSoup entscheiden, ist BS3 die bessere Wahl.
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']
Es kann viele doppelte Links zusammen mit externen und internen Links geben. Um zwischen den beiden zu unterscheiden und nur eindeutige Links mithilfe von Sets zu erhalten:
# 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)