webentwicklung-frage-antwort-db.com.de

Rufen Sie mit python und BeautifulSoup Links von der Webseite ab

Wie kann ich die Links einer Webseite abrufen und die URL-Adresse der Links mit Python kopieren?

126
NepUS

Hier ist ein kurzer Ausschnitt aus der SoupStrainer-Klasse in 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'])

Die BeautifulSoup-Dokumentation ist eigentlich ziemlich gut und deckt eine Reihe typischer Szenarien ab:

http://www.crummy.com/software/BeautifulSoup/documentation.html

Bearbeiten: Beachten Sie, dass ich die SoupStrainer-Klasse verwendet habe, weil sie ein bisschen effizienter ist (in Bezug auf Speicher und Geschwindigkeit), wenn Sie wissen, was Sie im Voraus analysieren.

173
ars

Der Vollständigkeit halber die BeautifulSoup 4-Version, die auch die vom Server bereitgestellte Codierung verwendet:

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']

oder die Python 3 Version:

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'])

und eine Version mit der requests Bibliothek , die, wie geschrieben, sowohl in Python 2 als auch in 3 funktioniert:

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'])

Der soup.find_all('a', href=True) -Aufruf findet alle <a> - Elemente, die ein href -Attribut haben. Elemente ohne das Attribut werden übersprungen.

Die Entwicklung von BeautifulSoup 3 wurde im März 2012 eingestellt. Neue Projekte sollten eigentlich immer BeautifulSoup 4 verwenden.

Beachten Sie, dass Sie das Dekodieren des HTML-Codes von Bytes zu BeautifulSoup lassen sollten. Sie können BeautifulSoup über den in den HTTP-Antwort-Headern gefundenen Zeichensatz informieren, um die Dekodierung zu unterstützen. Dies kann jedoch falsch sein und mit den <meta> - Header-Informationen im Konflikt stehen HTML selbst. Aus diesem Grund wird die interne Klassenmethode EncodingDetector.find_declared_encoding() von BeautifulSoup verwendet, um sicherzustellen, dass solche eingebetteten Codierungshinweise einen falsch konfigurierten Server überraschen.

Bei requests ist das Attribut response.encoding Standardmäßig Latin-1, wenn die Antwort einen Mimetyp text/* Aufweist, auch wenn kein Zeichensatz zurückgegeben wurde. Dies stimmt mit den HTTP-RFCs überein, ist jedoch bei Verwendung mit HTML-Parsing schmerzhaft. Daher sollten Sie dieses Attribut ignorieren, wenn im Content-Type-Header kein charset festgelegt ist.

61
Martijn Pieters

Andere haben BeautifulSoup empfohlen, aber es ist viel besser, lxml zu verwenden. Trotz seines Namens eignet es sich auch zum Parsen und Scrapen von HTML. Es ist viel, viel schneller als BeautifulSoup und 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 erlernen möchten.

Ian Blicking stimmt z .

Es gibt keinen Grund mehr, BeautifulSoup zu verwenden, es sei denn, Sie arbeiten mit Google App Engine oder einem anderen Programm, bei dem nicht nur Python 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 so 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
48
aehlke
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'
27
Andrew Johnson

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'))
10
Sentient07

Unter der Haube verwendet BeautifulSoup jetzt lxml. Anfragen, lxml & Listenverständnisse 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 "if '//' und 'url.com' nicht in x" eine einfache Methode, um die URL-Liste der 'internen' Navigations-URLs der Site usw. zu löschen.

8
cheekybastard

Um alle Links zu finden, verwenden wir in diesem Beispiel das urllib2-Modul zusammen mit dem re.module * eines der Die leistungsstärkste Funktion im re-Modul 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 zurück von Zeichenfolgen, 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
4
Mayur Ingle

nur um die Links zu bekommen, 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 weiterhin bevorzugt.

3
ghostdog74

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
3
Ricky Wilson

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]))
3
ahmadh

Verknüpfungen können sich in 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 starts with ^, um anzugeben, dass eines dieser Attribute 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)

Attribut = Wertselektoren

[attr ^ = value]

Stellt Elemente mit dem Attributnamen attr dar, denen der Wert vorangestellt wird.

2
QHarr

Hier ist ein Beispiel mit der von @ars akzeptierten Antwort und dem BeautifulSoup4, requests und wget Module, um 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)
1
Blairg23

Der eigene Parser von BeatifulSoup kann langsam sein. Möglicherweise ist es sinnvoller, lxml zu verwenden, das in der Lage ist, direkt von einer URL aus zu analysieren (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 Links oder um absolute Links aus dem 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 *.mp3 Akzeptiert. Einzelne und doppelte Punkte in den relativen Pfaden werden zwar nicht behandelt, aber bisher hatte ich keine Notwendigkeit dafür. Wenn Sie URL-Fragmente analysieren müssen, die ../ Oder ./ Enthalten, ist rlparse.urljoin möglicherweise hilfreich.

[~ # ~] note [~ # ~] : Das direkte Parsen von URLs in lxml behandelt das Laden von https nicht und nicht Redirects ausführen. Aus diesem Grund wird in der folgenden Version urllib2 + lxml verwendet.

#!/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 __== '__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"
1
ccpizza

Ich fand die Antwort von @ Blairg23 funktionierend nach der folgenden Korrektur (die das Szenario abdeckt, in dem es nicht richtig funktionierte):

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.

1
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']
0
Tilak Patidar