Python Web Scraping - BeautifulSoup
Python Web Scraping se refiere al proceso de extraer automáticamente información de Internet mediante la escritura de programas en Python.
El flujo básico de un web scraper generalmente incluye enviar solicitudes HTTP para obtener el contenido de la página web, analizar la página y extraer datos, y luego almacenar los datos.
El rico ecosistema de Python lo convierte en un lenguaje popular para desarrollar web scrapers, especialmente debido a su potente soporte de librerías.
En general, el proceso de un web scraper se puede dividir en los siguientes pasos:
- Enviar solicitudes HTTP: el web scraper obtiene la página HTML del sitio web objetivo mediante solicitudes HTTP; las librerías comunes incluyen
requests。 - Analizar el contenido HTML: después de obtener la página HTML, el web scraper necesita analizar el contenido y extraer datos; las librerías comunes son
BeautifulSoup、lxml、Scrapyetc. - Extraer datos: extraer los datos necesarios localizando elementos HTML (como etiquetas, atributos, nombres de clase, etc.).
- Almacenar datos: almacenar los datos extraídos en bases de datos, archivos CSV, archivos JSON u otros formatos para su uso o análisis posterior.
Este capítulo presenta principalmente BeautifulSoup, que es una librería de Python para analizar documentos HTML y XML, capaz de extraer datos de páginas web, y se usa comúnmente para web scraping y minería de datos.

BeautifulSoup
BeautifulSoup es una librería de Python para extraer datos de páginas web, especialmente adecuada para analizar archivos HTML y XML.
BeautifulSoup puede extraer y manipular el contenido de las páginas web proporcionando una API simple, siendo muy adecuado para tareas de web scraping y extracción de datos.
Instalar BeautifulSoup
Para usar BeautifulSoup, es necesario instalar beautifulsoup4 y lxml o html.parser (un analizador de HTML).
Podemos usar pip para instalar estas dependencias:
pip install beautifulsoup4 pip install lxml # 推荐使用 lxml 作为解析器(速度更快)
Si no tienes lxml, puedes usar el html.parser integrado de Python como analizador.
Uso básico
BeautifulSoup se utiliza para analizar datos HTML o XML, y proporciona varios métodos para navegar, buscar y modificar el árbol de análisis.
Las operaciones comunes de BeautifulSoup incluyen buscar etiquetas, obtener atributos de etiquetas, extraer texto, etc.
Para usar BeautifulSoup, primero debes importar BeautifulSoup y cargar la página HTML en un objeto BeautifulSoup.
Normalmente, primero usarás una librería de web scraping (comorequests) para obtener el contenido de la página web:
Ejemplo
import requests
# Usar requests para obtener el contenido de la página web
url = 'https://cn.bing.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
response = requests.get(url)
# Usar BeautifulSoup para analizar la página web
soup = BeautifulSoup(response.text, 'lxml') # Usar el analizador lxml
# Analizar el contenido de la página web con el analizador html.parser
# soup = BeautifulSoup(response.text, 'html.parser')
Obtener el título de la página web:
Ejemplo
import requests
# Especifica el sitio web del que deseas obtener el título
url = 'https://cn.bing.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
# Enviar una solicitud HTTP para obtener el contenido de la página web
response = requests.get(url)
# Problema de caracteres chinos ilegibles
response.encoding = 'utf-8'
# Asegurarse de que la solicitud sea exitosa
if response.status_code == 200:
# Usar BeautifulSoup para analizar el contenido de la página web
soup = BeautifulSoup(response.text, 'lxml')
# Buscar la etiqueta <title>
title_tag = soup.find('title')
# Imprimir el texto del título
if title_tag:
print(title_tag.get_text())
else:
print("No se encontró la etiqueta <title>")
else:
print("Solicitud fallida, código de estado:", response.status_code)
Al ejecutar el código anterior, el título de salida es:
搜索 - Microsoft 必应
Problema de caracteres chinos ilegibles
Al usar la librería requests para obtener páginas web en chino, es posible encontrar problemas de codificación que impiden que el contenido chino se muestre correctamente. Para garantizar que las páginas web chinas se obtengan y se muestren correctamente, normalmente es necesario gestionar la codificación de caracteres de la página web.
Detección automática de codificación: requests normalmente infiere la codificación de la página web según el Content-Type en los encabezados de respuesta, pero a veces puede ser inexacto; en ese caso, se puede usar chardet para detectar la codificación automáticamente.
Ejemplo
url = 'https://cn.bing.com/'
response = requests.get(url)
# Usar chardet para detectar la codificación automáticamente
import chardet
encoding = chardet.detect(response.content)['encoding']
print(encoding)
response.encoding = encoding
Al ejecutar el código anterior, la salida es:
utf-8
Si conoces la codificación de la página web (por ejemplo, utf-8 o gbk), puedes configurarla directamente.response.encoding:
response.encoding = 'utf-8' # 或者 'gbk',根据实际情况选择
Buscar etiquetas
BeautifulSoup proporciona varios métodos para buscar etiquetas en la página web; los más comunes incluyenfind()yfind_all()。
find()Devuelve la primera etiqueta que coincidafind_all()Devuelve todas las etiquetas que coincidan
Ejemplo
import requests
# Especifica el sitio web del que deseas obtener el título
url = 'https://www.baidu.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
# Enviar una solicitud HTTP para obtener el contenido de la página web
response = requests.get(url)
# Problema de caracteres chinos ilegibles
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'lxml')
# Buscar la primera etiqueta <a>
first_link = soup.find('a')
print(first_link)
print("----------------------------")
# Obtener el atributo href de la primera etiqueta <a>
first_link_url = first_link.get('href')
print(first_link_url)
print("----------------------------")
# Buscar todas las etiquetas <a>
all_links = soup.find_all('a')
print(all_links)
El resultado de salida es similar a:
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a> ---------------------------- http://news.baidu.com ---------------------------- [<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123</a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>,
Obtener el texto de una etiqueta
Puedes, medianteget_text()los atributos, acceder a las etiquetas padre e hija de una etiqueta:
Ejemplo
import requests
# Especifica el sitio web del que deseas obtener el título
url = 'https://www.baidu.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
# Enviar una solicitud HTTP para obtener el contenido de la página web
response = requests.get(url)
# Problema de caracteres chinos ilegibles
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'lxml')
# Obtener el contenido de texto de la primera etiqueta <p>
paragraph_text = soup.find('p').get_text()
# Obtener todo el contenido de texto de la página
all_text = soup.get_text()
print(all_text)
El resultado de salida es similar a:
Busca en Baidu y lo sabrás.
Buscar etiquetas hijas y padres
Puedes, medianteparentychildrenlos atributos, acceder a las etiquetas padre e hija:# 获取当前标签的父标签 parent_tag = first_link.parent # 获取当前标签的所有子标签 children = first_link.children
Ejemplo
import requests
# Especifica el sitio web del que deseas obtener el título
url = 'https://www.baidu.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
# Enviar una solicitud HTTP para obtener el contenido de la página web
response = requests.get(url)
# Problema de caracteres chinos ilegibles
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'lxml')
# Buscar la primera etiqueta <a>
first_link = soup.find('a')
print(first_link)
print("----------------------------")
# Obtener la etiqueta padre de la etiqueta actual
parent_tag = first_link.parent
print(parent_tag.get_text())
El resultado de salida es similar a:
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a> ---------------------------- 新闻 hao123 地图 视频 贴吧 登录 更多产品
Buscar etiquetas con atributos específicos
Puedes buscar etiquetas con atributos específicos pasando atributos.
Por ejemplo, para buscar todas las etiquetas div con la clase example-class:
# 查找所有 class="example-class" 的 <div> 标签
divs_with_class = soup.find_all('div', class_='example-class')
# 查找具有 id="unique-id" 的 <p> 标签
unique_paragraph = soup.find('p', id='unique-id')
Obtener el botón de búsqueda con id su:

Ejemplo
import requests
# Especifica el sitio web del que deseas obtener el título
url = 'https://www.baidu.com/' # Obtener el contenido de la página web del motor de búsqueda Bing
# Enviar una solicitud HTTP para obtener el contenido de la página web
response = requests.get(url)
# Problema de caracteres chinos ilegibles
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'lxml')
# Buscar la etiqueta <input> con id="unique-id"
unique_input = soup.find('input', id='su')
input_value = unique_input['value'] # Obtener el valor del campo de entrada input
print(input_value)
El resultado de salida es:
Buscar en Baidu.
Uso avanzado
Selectores CSS
BeautifulSoup también admite la búsqueda de etiquetas mediante selectores CSS.
El método select() permite buscar etiquetas usando una sintaxis de selector similar a jQuery:
# 使用 CSS 选择器查找所有 class 为 'example' 的 <div> 标签
example_divs = soup.select('div.example')
# 查找所有 <a> 标签中的 href 属性
links = soup.select('a[href]')
Manejo de etiquetas anidadas
BeautifulSoup admite estructuras HTML profundamente anidadas; puedes manejar estas estructuras buscando etiquetas hijas de forma recursiva:
# 查找嵌套的 <div> 标签
nested_divs = soup.find_all('div', class_='nested')
for div in nested_divs:
print(div.get_text())
Modificar el contenido de la página web
BeautifulSoup te permite modificar el contenido HTML.
Podemos modificar los atributos de las etiquetas, el texto o eliminar etiquetas:
Ejemplo
first_link['href'] = 'http://new-url.com'
# Modificar el contenido de texto de la primera etiqueta <p>
first_paragraph = soup.find('p')
first_paragraph.string = 'Updated content'
# Eliminar una etiqueta
first_paragraph.decompose()
Convertir a cadena
Puedes convertir el objeto BeautifulSoup analizado de vuelta a una cadena HTML:
# 转换为字符串 html_str = str(soup)
Atributos y métodos de BeautifulSoup
A continuación se presentan los atributos y métodos más utilizados en BeautifulSoup:
| Métodos/Atributos | Descripción | Ejemplo |
|---|---|---|
BeautifulSoup() | Se utiliza para analizar documentos HTML o XML y devolver un objeto BeautifulSoup. | soup = BeautifulSoup(html_doc, 'html.parser') |
.prettify() | Formatea y embellece el contenido del documento, generando una cadena estructurada. | print(soup.prettify()) |
.find() | Buscar la primera etiqueta que coincida. | tag = soup.find('a') |
.find_all() | Buscar todas las etiquetas que coincidan y devolver una lista. | tags = soup.find_all('a') |
.find_all_next() | Buscar todas las etiquetas que cumplan las condiciones después de la etiqueta actual. | tags = soup.find('div').find_all_next('p') |
.find_all_previous() | Buscar todas las etiquetas que cumplan las condiciones antes de la etiqueta actual. | tags = soup.find('div').find_all_previous('p') |
.find_parent() | Devolver la etiqueta padre de la etiqueta actual. | parent = tag.find_parent() |
.find_all_parents() | Buscar todas las etiquetas padre de la etiqueta actual. | parents = tag.find_all_parents() |
.find_next_sibling() | Buscar la siguiente etiqueta hermana de la etiqueta actual. | next_sibling = tag.find_next_sibling() |
.find_previous_sibling() | Buscar la etiqueta hermana anterior de la etiqueta actual. | prev_sibling = tag.find_previous_sibling() |
.parent | Obtener la etiqueta padre de la etiqueta actual. | parent = tag.parent |
.next_sibling | Obtener la siguiente etiqueta hermana de la etiqueta actual. | next_sibling = tag.next_sibling |
.previous_sibling | Obtener la etiqueta hermana anterior de la etiqueta actual. | prev_sibling = tag.previous_sibling |
.get_text() | Extraer el contenido de texto dentro de la etiqueta, ignorando todas las etiquetas HTML. | text = tag.get_text() |
.attrs | Devolver todos los atributos de la etiqueta, representados como un diccionario. | href = tag.attrs['href'] |
.string | Obtener el contenido de cadena dentro de la etiqueta. | string_content = tag.string |
.name | Devolver el nombre de la etiqueta. | tag_name = tag.name |
.contents | Devolver todos los elementos hijos de la etiqueta, en forma de lista. | children = tag.contents |
.descendants | Devolver todos los elementos descendientes de la etiqueta, en forma de generador. | for child in tag.descendants: print(child) |
.parent | Obtener la etiqueta padre de la etiqueta actual. | parent = tag.parent |
.previous_element | Obtener el elemento anterior de la etiqueta actual (sin incluir texto). | prev_elem = tag.previous_element |
.next_element | Obtener el elemento siguiente de la etiqueta actual (sin incluir texto). | next_elem = tag.next_element |
.decompose() | Eliminar la etiqueta actual y su contenido del árbol. | tag.decompose() |
.unwrap() | Quitar la etiqueta en sí, conservando solo su contenido hijo. | tag.unwrap() |
.insert() | Insertar una nueva etiqueta o texto dentro de la etiqueta. | tag.insert(0, new_tag) |
.insert_before() | Insertar una nueva etiqueta antes de la etiqueta actual. | tag.insert_before(new_tag) |
.insert_after() | Insertar una nueva etiqueta después de la etiqueta actual. | tag.insert_after(new_tag) |
.extract() | Eliminar la etiqueta y devolverla. | extracted_tag = tag.extract() |
.replace_with() | Reemplazar la etiqueta actual y su contenido. | tag.replace_with(new_tag) |
.has_attr() | Verificar si la etiqueta tiene el atributo especificado. | if tag.has_attr('href'): |
.get() | Obtener el valor del atributo especificado. | href = tag.get('href') |
.clear() | Vaciar todo el contenido de la etiqueta. | tag.clear() |
.encode() | Codificar el contenido de la etiqueta como flujo de bytes. | encoded = tag.encode() |
.is_empty_element | Verificar si la etiqueta es un elemento vacío (por ejemplo,<br>、<img>etc.). | if tag.is_empty_element: |
.is_ancestor_of() | Verificar si la etiqueta actual es un elemento ancestro de la etiqueta especificada. | if tag.is_ancestor_of(another_tag): |
.is_descendant_of() | Verificar si la etiqueta actual es un elemento descendiente de la etiqueta especificada. | if tag.is_descendant_of(another_tag): |
Otros atributos
| Métodos/Atributos | Descripción | Ejemplo |
|---|---|---|
.style | Obtener el estilo en línea de la etiqueta. | style = tag['style'] |
.id | Obtener de la etiquetaidel atributo. | id = tag['id'] |
.class_ | Obtener de la etiquetaclassel atributo. | class_name = tag['class'] |
.string | Obtener el contenido de cadena dentro de la etiqueta, ignorando otras etiquetas. | content = tag.string |
.parent | Obtener el elemento padre de la etiqueta. | parent = tag.parent |
Otros
| Métodos/Atributos | Descripción | Ejemplo |
|---|---|---|
find_all(string) | Buscar etiquetas coincidentes usando una cadena. | tag = soup.find_all('div', class_='container') |
find_all(id) | Buscar especificadaidde la etiqueta. | tag = soup.find_all(id='main') |
find_all(attrs) | Buscar etiquetas con el atributo especificado. | tag = soup.find_all(attrs={"href": "http://example.com"}) |