Mi trabajo de entrada de rastreador (1)


1. Herramientas

  1. Entorno de desarrollo: Python3.7 + Visual Studio Code
  2. Navegador: Google Chrome
  3. 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

  1. 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.
    Inserte la descripción de la imagen aquí
    Inserte la descripción de la imagen aquí
    Inserte la descripción de la imagen aquí
  2. 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.
    Inserte la descripción de la imagen aquí
  3. 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内容转换成文本格式,
                # 并且将里面的&nbsp(不间断空格)替换成空格
                # 将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内容转换成文本格式,
                # 并且将里面的&nbsp(不间断空格)替换成空格
                # 将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

  1. 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.
    Inserte la descripción de la imagen aquí
    Inserte la descripción de la imagen aquí
  2. 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
    Inserte la descripción de la imagen aquí
    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

Inserte la descripción de la imagen aquí
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

  1. 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
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
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.
Inserte la descripción de la imagen aquí
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

  1. Análisis práctico de inicio rápido del rastreador web Python3
  2. Python3 crawler chino distorsionado resolución de problemas? (Beautifulsoup4)

Primera modificación: cambie la etiqueta br a una nueva línea

Supongo que te gusta

Origin blog.csdn.net/qq_36439722/article/details/106028350
Recomendado
Clasificación