Tabla de contenido
1. Herramientas
- Entorno de desarrollo: Python3.7 + Visual Studio Code
- Navegador: Google Chrome
- Instalar la biblioteca de Python: solicitudes, utilizadas para obtener HTML, BeautifulSoup , utilizadas para analizar documentos HTML
2. Texto
2.1 URL
Objetivo: rastrear el sitio web de Xinbi Quge "Fighting Knives in the Snow" de los señores de la Ópera Fenghuo.
Dirección de la página del directorio: http://www.xbiquge.la/0/745/
2.2 Ideas
- Analice el código fuente de la página del catálogo y busque la etiqueta que guarda la URL de cada capítulo: haga clic con el botón derecho del ratón -> seleccione marcar (N) o presione F12, y saldrá el código fuente de la página web. Para encontrar la URL del catálogo, coloque el mouse en uno de los catálogos de capítulos y haga clic con el botón derecho, y el código fuente saltará al contenido correspondiente. Se puede ver que la URL de cada capítulo se almacena en la etiqueta div con el atributo id = "list". Solo necesita encontrar el div correspondiente al atributo, y luego encontrar todas las etiquetas a que contiene, que es para encontrar las URL de todos los capítulos.
- Analice el contenido de la página del capítulo: haga clic con el botón derecho en el contenido (texto) -> comprobar y vaya al contenido correspondiente al código fuente. Se encuentra que el contenido se almacena en la etiqueta div con el atributo id = "content", por lo que debe encontrar la etiqueta div correspondiente y luego generar el contenido.
- Idea general: obtenga la URL de cada capítulo en la página de la tabla de contenido—> recorra el contenido de cada capítulo a través de la URL de cada capítulo—> escriba en un archivo de texto (txt)
2.3 Implementación
2.3.1 Obtenga la URL de cada capítulo
def __get_Link_chapter(self):
'''在目录页获得各个章节的url.
解析目录页,通过属性找到存放各个章节url的div标签,
获取各个章节的url并且返回
'''
# 当请求发生异常:连接或者超时错误,等待1S再尝试
for try_counter in range(10):
try:
req_lp = requests.get(self.__url_lp, timeout=10)
break
except ConnectionError:
print('尝试获取目录页ConnectionError:%d' % (try_counter+1))
except TimeoutError:
print('尝试获取目录页TimeoutError:%d' % (try_counter+1))
except:
print('尝试获取目录页OtherError:%d' % (try_counter+1))
time.sleep(1)
if try_counter >= 9:
print('获取目录页失败')
return
else:
try:
req_lp.encoding = req_lp.apparent_encoding
# 建立BeautifulSoup对象,指定解析器lxml
bs_lp = BeautifulSoup(req_lp.text, 'lxml')
# 找到所有对应属性的div标签
div_list = bs_lp.find_all('div', attrs=self.__attrs_div_lp)
# 找到所有的a标签
link_chapter = []
for div in div_list:
link_chapter += div.find_all('a')
return link_chapter
except TypeError:
print('目录页解析异常:TypeError')
return
except:
print('目录页解析异常:OtherError')
return
2.3.2 Obtener el contenido de un capítulo
def __get_content_chapter(self, link):
'''获取章节内容.
:param link:在目录页解析后得到的a标签
内含章节名和url
'''
name_chapter = link.string
url_chapter = self.__url_ws + link['href'] # 拼接得到章节页url
# 在链接和读取过程中,出现异常的处理方式
# 这里出现异常的话循环10次,等待1S重新读取
for try_counter in range(10):
try:
# 超时设置为10S
req_ct = requests.get(url_chapter, timeout=10)
break
except ConnectionError:
print('尝试获取章节链接:ConnectionError%d' % (try_counter+1))
except TimeoutError:
print('尝试获取章节链接:TimeoutError%d' % (try_counter+1))
except:
print('尝试获取章节链接:OtherError%d' % (try_counter+1))
time.sleep(1)
if try_counter >= 9:
print('获取链接失败:'+name_chapter)
return name_chapter+'\n\n'
else:
try:
req_ct.encoding = self.__encode
# 建立BeautifulSoup对象
bs_ct = BeautifulSoup(
req_ct.text, 'lxml')
# 将找到的div内容转换成文本格式,
# 并且将里面的 (不间断空格)替换成空格
# 将br标签替换成换行符
content = bs_ct.find(
'div', attrs=self.__attrs_div_ct)
content = str(content).replace('<br/>','\n').replace('\xa0',' ')
content = BeautifulSoup(content,'lxml').get_text()
return name_chapter + '\n\n' + content + '\n\n'
except TypeError:
print('章节页解析异常:TypeError '+name_chapter)
return name_chapter+'\n\n'
except:
print('章节页解析异常:OtherError '+name_chapter)
return name_chapter+'\n\n'
2.3.3 Escribir contenido
def write(self, path_save):
'''写下载的文件到指定路径.
:param path_save:指定的保存路径
'''
# 在指定的文件夹路路径之下新建与书名同名的文本文件
path_save = path_save + '\\' + self.__name + '.txt'
# 获取各个章节的URL
link_chapter = self.__get_Link_chapter()
if link_chapter is None:
pass
else:
# 打开文件
with open(path_save, 'w+', encoding=self.__encode) as file:
for chapter, link in enumerate(link_chapter):
# 获取章节内容
content_chapter = self.__get_content_chapter(link)
file.write(content_chapter)
sys.stdout.write('下载进度:%.1f%%' % float(
chapter/len(link_chapter)*100)+'\r')
print('<<'+self.__name+'>>下载完成')
2.3.4 Código completo
from bs4 import BeautifulSoup
import requests
import time
import sys
class fiction():
def __init__(self, name, url_ws, url_lp, encode, attrs_div_lp={
}, attrs_div_ct={
}):
self.__name = name # 名字
self.__url_ws = url_ws # 网站url
self.__url_lp = url_lp # 链接(目录)页的url
self.__attrs_div_lp = attrs_div_lp # 链接(目录页)存放各个章节链接的div标签属性
self.__attrs_div_ct = attrs_div_ct # 章节页存放内容的div标签属性
self.__encode = encode # 指定编码格式
def Update(self, name, url_ws, url_lp, encode, attrs_div_lp={
}, attrs_div_ct={
}):
'''重置参数
必须同时重置所有参数,否则可能出现错误
'''
self.__name = name # 名字
self.__url_ws = url_ws # 网站url
self.__url_lp = url_lp # 链接(目录)页的url
self.__attrs_div_lp = attrs_div_lp # 链接(目录页)存放各个章节链接的div标签属性
self.__attrs_div_ct = attrs_div_ct # 章节页存放内容的div标签属性
self.__encode = encode
def __get_Link_chapter(self):
'''在目录页获得各个章节的url.
解析目录页,通过属性找到存放各个章节url的div标签,
获取各个章节的url并且返回
'''
# 当请求发生异常:连接或者超时错误,等待1S再尝试
for try_counter in range(10):
try:
req_lp = requests.get(self.__url_lp, timeout=10)
break
except ConnectionError:
print('尝试获取目录页ConnectionError:%d' % (try_counter+1))
except TimeoutError:
print('尝试获取目录页TimeoutError:%d' % (try_counter+1))
except:
print('尝试获取目录页OtherError:%d' % (try_counter+1))
time.sleep(1)
if try_counter >= 9:
print('获取目录页失败')
return
else:
try:
req_lp.encoding = req_lp.apparent_encoding
# 建立BeautifulSoup对象,指定解析器lxml
bs_lp = BeautifulSoup(req_lp.text, 'lxml')
# 找到所有对应属性的div标签
div_list = bs_lp.find_all('div', attrs=self.__attrs_div_lp)
# 找到所有的a标签
link_chapter = []
for div in div_list:
link_chapter += div.find_all('a')
return link_chapter
except TypeError:
print('目录页解析异常:TypeError')
return
except:
print('目录页解析异常:OtherError')
return
def __get_content_chapter(self, link):
'''获取章节内容.
:param link:在目录页解析后得到的a标签
内含章节名和url
'''
name_chapter = link.string
url_chapter = self.__url_ws + link['href'] # 拼接得到章节页url
# 在链接和读取过程中,出现异常的处理方式
# 这里出现异常的话循环10次,等待1S重新读取
for try_counter in range(10):
try:
# 超时设置为10S
req_ct = requests.get(url_chapter, timeout=10)
break
except ConnectionError:
print('尝试获取章节链接:ConnectionError%d' % (try_counter+1))
except TimeoutError:
print('尝试获取章节链接:TimeoutError%d' % (try_counter+1))
except:
print('尝试获取章节链接:OtherError%d' % (try_counter+1))
time.sleep(1)
if try_counter >= 9:
print('获取链接失败:'+name_chapter)
return name_chapter+'\n\n'
else:
try:
req_ct.encoding = self.__encode
# 建立BeautifulSoup对象
bs_ct = BeautifulSoup(
req_ct.text, 'lxml')
# 将找到的div内容转换成文本格式,
# 并且将里面的 (不间断空格)替换成空格
# 将br标签换成换行符
content = bs_ct.find(
'div', attrs=self.__attrs_div_ct)
content = str(content).replace('<br/>','\n').replace('\xa0',' ')
content = BeautifulSoup(content,'lxml').get_text()
return name_chapter + '\n\n' + content + '\n\n'
except TypeError:
print('章节页解析异常:TypeError '+name_chapter)
return name_chapter+'\n\n'
except:
print('章节页解析异常:OtherError '+name_chapter)
return name_chapter+'\n\n'
def write(self, path_save):
'''写下载的文件到指定路径.
:param path_save:指定的保存路径
'''
# 在指定的文件夹路路径之下新建与书名同名的文本文件
path_save = path_save + '\\' + self.__name + '.txt'
# 获取各个章节的URL
link_chapter = self.__get_Link_chapter()
if link_chapter is None:
pass
else:
# 打开文件
with open(path_save, 'w+', encoding=self.__encode) as file:
for chapter, link in enumerate(link_chapter):
# 获取章节内容
content_chapter = self.__get_content_chapter(link)
file.write(content_chapter)
sys.stdout.write('下载进度:%.1f%%' % float(
chapter/len(link_chapter)*100)+'\r')
print('<<'+self.__name+'>>下载完成')
if __name__ == '__main__':
start = time.time()
f = fiction(name='雪中悍刀行',
url_ws='http://www.xbiquge.la',
url_lp='http://www.xbiquge.la/0/745/',
attrs_div_lp={
'id': 'list'},
attrs_div_ct={
'id': 'content'},
encode='utf-8')
f.write(r'C:\Users\HP\Desktop\pytxt')
stop = time.time()
print('用时:%ds' % (stop-start))
3. Resumen
3.1 conocimientos básicos de HTML
Conocimientos básicos de html: tutorial para principiantes-tutorial HTML
3.2 Método de biblioteca de solicitudes
- get (): Obtiene el contenido de la respuesta del servidor. Nota: Es mejor establecer el período de tiempo de espera; de lo contrario, si el servidor no responde, la solicitud se enviará todo el tiempo y el programa siempre se bloqueará en ese lugar y no se informará ninguna excepción o error.
- Respecto al problema de codificación: Es mejor especificar el método de codificación. La codificación adivinada por Requests puede ser inexacta y puede ocurrir una excepción al escribir texto más tarde. Puede hacer referencia a un análisis específico, saber casi el
conjunto de caracteres html en la sección principal para especificar la codificación de origen, la codificación y las inconsistencias reales que a veces se describen, esta vez utilizando la codificación especificada Response.apparent_encoding.
req_lp.encoding = req_lp.apparent_encoding
3. Para obtener más detalles sobre la biblioteca de solicitudes, consulte los documentos oficiales: inicio rápido , uso avanzado , interfaz de desarrollo
3.3 biblioteca BeauifulSoup
- Crea un objeto BeauifulSoup:
bs_lp = BeautifulSoup(req_lp.text, 'lxml')
El primer parámetro es el documento HTML que necesita ser analizado, y el segundo parámetro es el analizador de documentos especificado
2. Método find_all (): encuentra todas las etiquetas que cumplen con las condiciones de filtro bajo la etiqueta de etiqueta actual y devuelve un bs4.element. Tipo ResultSet , de hecho se puede utilizar como una lista.
3. Codificación: Después de usar BeautifulSoup, ya sea que el documento HTML original tenga codificación gbk, codificación utf-8 u otra codificación, todo se convertirá a codificación Unicode, probablemente porque la codificación Unicode es compatible con todos los idiomas.
3.4 Escritura de archivos
Operación de archivos Python: tutorial novato-Método de archivo Python3 (archivo)
3.5 URL de cada capítulo
La URL de cada capítulo de la página del catálogo está incompleta y la URL del sitio web debe empalmarse para ser una URL completa.
url_chapter = self.__url_ws + link['href'] # 拼接得到章节页url
4. Referencia
- Análisis práctico de inicio rápido del rastreador web Python3
- Python3 crawler chino distorsionado resolución de problemas? (Beautifulsoup4)
Primera modificación: cambie la etiqueta br a una nueva línea