¿Cómo puedo recuperar los enlaces de una página web y copiar la dirección URL de los enlaces utilizando Python?recuperar enlaces de la página web usando Python y BeautifulSoup
Respuesta
Aquí está un breve fragmento utilizando la clase SoupStrainer en BeautifulSoup:
import httplib2
from BeautifulSoup import BeautifulSoup, SoupStrainer
http = httplib2.Http()
status, response = http.request('http://www.nytimes.com')
for link in BeautifulSoup(response, parseOnlyThese=SoupStrainer('a')):
if link.has_attr('href'):
print link['href']
La documentación BeautifulSoup es en realidad bastante bueno, y abarca una serie de escenarios típicos:
http://www.crummy.com/software/BeautifulSoup/documentation.html
Editar: Tenga en cuenta que utilicé la clase SoupStrainer porque es un poco más eficiente (memoria y velocidad), si sabe lo que está analizando por adelantado.
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'
sólo para conseguir los enlaces, sin B.soup y expresiones regulares:
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]
para operaciones más complejas, de BSoup supuesto, todavía se prefiere.
Otros han recomendado BeautifulSoup, pero es mucho mejor usar lxml. A pesar de su nombre, también es para analizar y raspar HTML. Es mucho, mucho más rápido que BeautifulSoup, e incluso maneja HTML "roto" mejor que BeautifulSoup (su reclamo de fama). También tiene una API de compatibilidad para BeautifulSoup si no desea aprender la API lxml.
No hay ninguna razón para usar BeautifulSoup, a menos que esté en Google App Engine o algo en que no esté permitido nada que no sea puramente Python.
lxml.html también es compatible con los selectores de CSS3 por lo que este tipo de cosas es trivial.
Un ejemplo con lxml y XPath se vería así:
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
BeautifulSoup 4 usará 'lxml' como el analizador predeterminado si está instalado. –
Por qué no usar expresiones regulares:
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]))
Me encantaría poder entender esto, ¿dónde puedo averiguar de manera eficiente qué '(r"
Realmente una mala idea. HTML roto en todas partes. – Ufoguy
¿Por qué no utilizar expresiones regulares para analizar html: http: // stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags? page = 1 & tab = votes # 1732454 – allcaps
Bajo el capó BeautifulSoup ahora utiliza lxml. Solicitudes, lxml & lista de comprensiones hace un combo asesino.
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]
En la lista comp, el "si '//' y 'url.com' no en x" es un método simple para fregar la lista de direcciones URL url de navegación 'internos' los sitios, etc.
Si se trata de un repositorio, ¿por qué la publicación original no incluye: 1. solicita 2.list comp 3. logic para eliminar los enlaces internos y basura del sitio? Intenta comparar los resultados de las dos publicaciones, mi comp de lista hace un trabajo sorprendentemente bueno fregando los enlaces basura. – cheekybastard
El OP no solicitó esas características y la parte que solicitó ya se ha publicado y resuelto utilizando el mismo método exacto que usted publica. Sin embargo, eliminaré la votación negativa ya que la comprensión de la lista agrega valor para las personas que sí desean esas funciones y las menciona explícitamente en el cuerpo de la publicación. Además, podría usar el representante :) – dotancohen
El código siguiente es para recuperar todos los enlaces disponibles en una página web utilizando urllib2 y 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'))
Para completarlo, la versión BeautifulSoup 4, haciendo uso de la codificación proporcionada por el servidor, así:
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']
o la versión 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'])
y una versión usando el requests
library, que como escrito funcionará en tanto Python 2 y 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'])
La llamada soup.find_all('a', href=True)
encuentra todos <a>
elementos que tienen un atributo href
; los elementos sin el atributo se omiten.
BeautifulSoup 3 detuvo el desarrollo en marzo de 2012; nuevos proyectos realmente deberían usar BeautifulSoup 4, siempre.
Tenga en cuenta que debe dejar de decodificar el HTML de los bytes a BeautifulSoup. Puede informar BeautifulSoup del juego de caracteres encontrado en los encabezados de respuesta HTTP para ayudar en la decodificación, pero puede estar equivocado y en conflicto con una información de encabezado <meta>
que se encuentra en el HTML, por lo que lo anterior usa el método de clase interna BeautifulSoup EncodingDetector.find_declared_encoding()
para asegurarse de que tales sugerencias de codificación incrustadas ganen sobre un servidor mal configurado.
Con requests
, el atributo response.encoding
tiene como valor predeterminado Latin-1 si la respuesta tiene un tipo mimet text/*
, incluso si no se devolvió ningún conjunto de caracteres. Esto es coherente con los RFC de HTTP, pero es doloroso cuando se utiliza con el análisis HTML, por lo que debe ignorar ese atributo cuando no se establece charset
en el encabezado Content-Type.
¿Hay algo así como StrainedSoup for bs4? (No lo necesito ahora, solo me pregunto, si hay algo que quiera agregar) –
@AnttiHaapala: ¿'SoupStrainer' te refieres? No [fue a ninguna parte, todavía es parte del proyecto] (https://www.crummy.com/software/BeautifulSoup/bs4/doc/#soupstrainer). –
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']
Este script hace lo que usted busca, pero también resuelve los enlaces relativos a los enlaces absolutos.
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
permite encontrar todos los enlaces, vamos a utilizar en este ejemplo el módulo urllib2 junto con el re.module * Una de las funciones más poderoso del módulo re es "re.findall() ". Mientras re.search() se utiliza para encontrar el primer partido para un patrón, re.findall() busca todos los los partidos y los devuelve como una lista de cadenas, donde cada cadena que representa un partido *
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
El analizador propio de BeatifulSoup puede ser lento. Puede ser más factible usar lxml que es capaz de analizar directamente desde una URL (con algunas limitaciones que se mencionan a continuación).
import lxml.html
doc = lxml.html.parse(url)
links = doc.xpath('//a[@href]')
for link in links:
print link.attrib['href']
El código anterior devuelve los enlaces como es, y en la mayoría de los casos sería enlaces relativos o absolutos de la raíz del sitio. Como mi caso de uso consistía en extraer solo cierto tipo de enlaces, a continuación se muestra una versión que convierte los enlaces a URL completas y que acepta un patrón glob como *.mp3
. Sin embargo, no manejará puntos individuales y dobles en las rutas relativas, pero hasta ahora no tuve la necesidad de hacerlo. Si necesita analizar fragmentos de URL que contengan ../
o ./
, entonces urlparse.urljoin puede ser útil.
NOTA: lxml directa análisis de URL no se ocupa de la carga de https
y no hace redirecciones, por lo que por esta razón la versión más adelante está utilizando 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
El uso es el siguiente:
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' solo puede manejar entradas válidas, ¿cómo puede reemplazar' BeautifulSoup'? – alexis
@alexis: Creo que 'lxml.html' es un poco más indulgente que' lxml.etree'. Si su entrada no está bien formada, puede establecer explícitamente el analizador BeautifulSoup: http://lxml.de/elementsoup.html. Y si vas con BeatifulSoup entonces BS3 es una mejor opción. – ccpizza
Aquí hay un ejemplo usando @ars aceptados respuesta y la BeautifulSoup4
, requests
y wget
módulos para manejar las descargas.
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)
he encontrado la respuesta por @ Blairg23 de trabajo, después de la siguiente corrección (que cubre el escenario en el que no funcionó correctamente):
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)
Para Python 3:
urllib.parse.urljoin
tiene que ser utilizado para obtener la URL completa en su lugar.
- 1. Usando urllib y BeautifulSoup para recuperar información de la web con Python
- 2. ¿Cómo puedo recuperar el título de la página de una página web usando Python?
- 3. ¿Cómo extraer enlaces de una página web usando lxml, XPath y Python?
- 4. Extraiga enlaces de una página web usando Go lang
- 5. Descargar todos los enlaces (documentos relacionados) en una página web usando Python
- 6. Analizando datos usando BeautifulSoup en Python
- 7. Python y BeautifulSoup problemas de codificación
- 8. HTML analizando con BeautifulSoup 4 y Python
- 9. Extraer enlaces de la página web utilizando R
- 10. web scraping para completar (y recuperar) formularios de búsqueda?
- 11. ¿Cómo recuperar una página web con C#?
- 12. BeautifulSoup Grab Visible página de texto
- 13. Optimizar código BeautifulSoup (Python)
- 14. ¿Cómo puedo ingresar datos en una página web para raspar la salida resultante usando Python?
- 15. Python: la forma más sencilla de eliminar texto de la lista de URL usando BeautifulSoup
- 16. Python BeautifulSoup XML Parsing
- 17. Página web redirigir a la página principal con CGI Python
- 18. Python beautifulsoup iterar sobre la tabla
- 19. Descargando una página web y todos sus archivos de recursos en Python
- 20. BeautifulSoup - ¿modificando todos los enlaces en una pieza de HTML?
- 21. Extraer datos de archivos HTML con BeautifulSoup y Python
- 22. Uso de memoria de Python con BeautifulSoup
- 23. BeautifulSoup y ASP.NET/C#
- 24. ¿Cómo puedo emular ": contiene" usando BeautifulSoup?
- 25. Web scraping con Python
- 26. Scraping para una "vista previa" de una página web - Python
- 27. módulo de Python BeautifulSoup anclas extracción href
- 28. Python Lambdas y enlaces de variable
- 29. ¿Cómo se usa Python para iniciar sesión en una página web y recuperar cookies para usarlas posteriormente?
- 30. Usando Python para desarrollar la aplicación web
+1, usar el filtro de sopa es una gran idea, ya que le permite eludir una gran cantidad de análisis innecesarios cuando lo único que busca son los enlaces. –
Lo edité para agregar una explicación similar antes de ver el comentario de Evan. ¡Gracias por notar eso, sin embargo! – ars
gracias, esto resuelve mi problema, con esto termino mi proyecto muchas gracias – NepUS