Magazine Downloader -- python campo con python-3.x campo con web-scraping camp codereview Relacionados El problema

Magpi Magazine Downloader


8
vote

problema

Español

He creado un programa simple en Python, que descarga todas las cuestiones de la revista MAGPI al analizar esto < / a> página web para enlaces que terminan en #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include "Headers/displayMenu.hpp" #include "Headers/add.hpp" #include "Headers/subtract.hpp" #include "Headers/multiply.hpp" #include "Headers/divide.hpp" #include "Headers/square.hpp" #include "Headers/raise.hpp" #include "Headers/log.hpp" #include "Headers/Sin.hpp" #include "Headers/square_root.hpp" #include "Headers/Tan.hpp" #include "Headers/Acos.hpp" #include "Headers/Ceil.hpp" #include "Headers/Cloor.hpp" using namespace std; 8 , luego descargándolas usando el módulo 99887766555443319 . También es compatible con las opciones de línea de comandos, utilizando el módulo void add(float a, float b, float c) { float result = a + b + c; std::cout<<result<<" "; } 020 :

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 1  

Estoy buscando formas de mejorar la Interfaz de usuario , la velocidad, y hacerla generalmente más limpia y más pythonic.

Código fuente:

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 2  

Lo siento por la extrema falta de comentarios y documentos DOCS, por lo que es lo que me enfocaré.

Casos de uso:

para descargar todo:

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 3  

para descargar todos los problemas regulares:

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 4  

para descargar los elementos esenciales de MAGPI:

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 5  

para ver pero no instalar problemas disponibles:

  void add(float a, float b, float c) {   float result = a + b + c;   std::cout<<result<<" "; } 6  

Otras opciones son las documentadas anteriormente.

Original en ingles

I have created a simple program in Python which downloades all issues of the MagPi magazine by parsing this web page for links ending in .pdf, then downloading them using the urllib module. It also supports command line options, using the argparse module:

$ ./magpi_downloader.py -h usage: magpi_downloader.py [-h] [-q] [-r] [--view] [-t FILETYPE] [-a] [-i]                            [-e]                            DIR [REMOTE_DIR]  Download issues of the MagPi magazine  positional arguments:   DIR               The directory to install into.   REMOTE_DIR        The directory to fetch from. Files must be links on that                     page. Works best with Apache servers with the default                     directory listing. Default: http://www.raspberrypi.org                     /magpi-issues/  optional arguments:   -h, --help        show this help message and exit   -q, --quiet       Silence progress output   -r, --reinstall   Reinstall all issues   --view            List the issues available for install   -t FILETYPE       The extension of the files to download. Default: pdf   -a, --all         Install all files with the right extension.   -i, --issues      Install the regular issues (default behavior)   -e, --essentials  Install the 'Essentials' collection 

I am looking for ways to improve the user interface, the speed, and making it generally cleaner and more pythonic.

Source code:

import urllib, os, re, time, sys, argparse from bs4 import BeautifulSoup  ISSUES_REGEX = u'MagPi[0-9]+' ESSENTIALS_REGEX = u'Essentials_.*'  def get_installed(directory):     if not os.path.exists(directory):         if not quiet:             print("Directory doesn't exist\nCreating new directory with the name {}".format(directory))         os.mkdir(directory)     for filename in os.listdir(directory):         if re.match(regex, filename):             yield filename  def download(filename, localfilename):     localfile = get_full_path(download_dir, localfilename)     try:         open(localfile, 'w').close()         urllib.request.urlretrieve(filename, localfile)     except KeyboardInterrupt:         print('Cleaning up...')         os.remove(localfile)         sys.exit()  def webopen(page):     return urllib.request.urlopen(page)  def get_links(soup):     for link in soup.find_all('a'):         yield link.get('href')  def get_issues(soup):     links = list(get_links(soup))     for link in links:         if re.match(regex, link):             yield link  def get_missing(installed, all_issues):     for issue in all_issues:         if not issue in installed:             yield issue  def get_full_path(directory, filename):     return os.path.join(directory, filename)  def to_install_info(directory):     page = webopen(remote_dir)     soup = BeautifulSoup(page)      issues = list(get_issues(soup))     installed = list(get_installed(directory))     missing = list(get_missing(installed, issues))     return issues, installed, missing  def install(missing):     for issue in missing:         print('Downloading {} '.format(issue))         download(get_full_path(remote_dir, issue), issue)         print('Done')  def install_quiet(missing):     for issue in missing:         download(get_full_path(remote_dir, issue), issue)  def print_to_install_info(issues, installed, missing):     print('{} Released:\n\n{}\n\n{} Installed:\n\n{}\n\n{} To install:\n\n{}'.format(len(issues), issues, len(installed), installed, len(missing), missing))  def install_all(missing):     install(missing)  def install_all_quiet(missing):     install_quiet(missing)  if __name__ == '__main__':     parser = argparse.ArgumentParser(description="Download issues of the MagPi magazine")     parser.add_argument('-q', '--quiet', action='store_true', help="Silence progress output")     parser.add_argument('-r', '--reinstall', action='store_true', help="Reinstall all issues")     parser.add_argument('--view', action='store_true', help="List the issues available for install")     parser.add_argument('-t',  dest='filetype', metavar='FILETYPE', type=str, action='store',             default=u'pdf', help="The extension of the files to download. Default: %(default)s")     parser.add_argument('-a', '--all', dest='types', action='store_const', const=u'.*',             help="Install all files with the right extension.")     parser.add_argument('-i', '--issues', dest='types', action='store_const', const=ISSUES_REGEX,             help='Install the regular issues (default behavior)')     parser.add_argument('-e', '--essentials', dest='types', action='store_const',             const=ESSENTIALS_REGEX, help="Install the 'Essentials' collection")     parser.add_argument('directory',  metavar='DIR', type=str,             help="The directory to install into.")     parser.add_argument('remote_dir',  metavar='REMOTE_DIR', type=str, nargs='?',             default='http://www.raspberrypi.org/magpi-issues/',             help="The directory to fetch from. Files must be links on that page. Works \                     best with Apache servers with the default directory listing. Default: %(default)s")      args = parser.parse_args()     download_dir = args.directory     remote_dir = args.remote_dir     types = args.types      if not types:         types = ISSUES_REGEX     regex = u"^{}\.{}$".format(types, args.filetype)     print(regex)     quiet = args.quiet     reinstall = args.reinstall     view = args.view      issues, installed, missing = to_install_info(download_dir)      if reinstall:         missing = issues         msg = 'Overwriting issues'     else: msg = 'Installing Issues'      if not quiet:         print_to_install_info(issues, installed, missing)          if view:             print('To install, run without the view flag.')         else:             print(msg)             install_all(missing)     else: install_all_quiet(missing) 

I am sorry for the extreme lack of comments and docstrings, so that is what I will focus on.

Usage cases:

To download everything:

$ ./magpi_downloader.py -a download_dir 

To download all regular issues:

$ ./magpi_downloader.py download_dir 

To download the MagPi essentials:

$ ./magpi_downloader.py -e download_dir 

To view but not install available issues:

$ ./magpi_downloader.py download_dir 

Other options are as documented above.

        

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 

El código en general no es legible . Es bastante largo, no hay una estructura modular, no hay comentarios y documentos significativos. Lo primero que haría es que es dividido en múltiples módulos agrupados lógicamente, definió las documentos documentes para cada una de las funciones (que en realidad pueden llevar a algunas funciones que se unen o incluso se eliminan).

Además, algunos de los bloques de código se pueden extraer en funciones separadas. Por ejemplo, aplique la Método de refactorización "Extraer método" y extraiga los "Argumentos de análisis de análisis con ArgarParse" en una función separada.

Ahora, vamos a revisar los problemas uno por uno:

  • Organización de importación: evite importar múltiples módulos incorporados en una sola línea. Las importaciones de terceros deben tener una nueva línea antes de ellas. Ponga 2 recién llegados después de todas las importaciones ( pautas de importación PEP8 )
  • Dado que está emitiendo múltiples solicitudes al mismo dominio, usaría 9988776655544334 MODIZO MANTENIMIENTO A Sesión de raspado web a través de requests.Session - Esto podría resultar en un aumento significativo de rendimiento:

    Entonces, si está realizando varias solicitudes al mismo host, la conexión TCP subyacente se reutilizará, lo que puede resultar en un aumento significativo de rendimiento

  • Al instanciar un objeto de "sopa", es altamente recomendable para especificar explícitamente el analizador subyacente para evitar dejarlo BeautifulSoup Haga esto automáticamente, puede elegir html.parser en su máquina, pero en la otra máquina, puede elegir lxml8 o html5lib que puede resultar en diferentes resultados de análisis (consulte diferencias entre los analizadores ):

      String0  
  • Puede mejorar la forma en que localiza los elementos en una página. Actualmente, está encontrando todos los enlaces a través de String1 y luego aplicando una expresión regular al 99887776655443312 valores de atributo. String3 puede hacer ambos en un solo comando "Buscar":

      String4  
  • El String5 puede beneficiarse de usar una cadena de línea múltiple (para evitar múltiples caracteres de nueva línea en la cadena de plantillas de formato)
  • A excepción de la impresión, el String6 y String7 Las funciones realmente se duplican entre sí. Tiene una sola función con String8 argumento, o, incluso mejor, use String9 Módulo con un nivel de registro configurable / controlable

  • VER SI PUEDE REEMPLAZAR String0 y un registro regular interno con una sola String1 (o String2 ) llamada.

 

The code overall is not readable. It's quite lengthy, there is no modular structure, no meaningful comments and docstrings. The first thing I would do is to split it into multiple modules grouped logically, define the docstrings for each of the functions (which may actually lead to some functions being joined together or even removed).

Also, some of the code blocks can be extracted into separate functions. For instance, apply the "Extract Method" refactoring method and extract the "parsing arguments with argparse" part into a separate function.

Now, let's go over the issues one by one:

  • import organization - avoid importing multiple built-in modules on a single line. Third-party imports need to have a newline before them. Put 2 newlines after all the imports (PEP8 import guidelines)
  • since you are issuing multiple requests to the same domain, I would use requests module maintaining a web-scraping session via requests.Session - this might result into a significant performance boost:

    So if you're making several requests to the same host, the underlying TCP connection will be reused, which can result in a significant performance increase

  • when instantiating a "soup" object, it's highly recommended to explicitly specify the underlying parser to avoid letting BeautifulSoup do this automatically - it might choose html.parser on your machine, but on the other machine, it may pick lxml or html5lib which may result into different parsing results (see Differences between parsers):

    soup = BeautifulSoup(page, "html.parser") # soup = BeautifulSoup(page, "html5lib") # soup = BeautifulSoup(page, "lxml") 
  • you can improve the way you locate the elements on a page. Currently, you are finding all the links via find_all("a") and then applying a regular expression to the href attribute values. BeautifulSoup can do both in a single "find" command:

    soup.find_all("a", href=re.compile(r"expression here")) 
  • the print_to_install_info() can benefit from using a multi-line string (to avoid multiple newline characters in the format template string)
  • except for printing, the install() and install_quiet() functions really duplicate each other. Either have a single function with quiet argument, or, even better, use logging module with a configurable/controllable log level

  • see if you can replace listdir() and an inner regex check with a single glob.glob() (or glob.iglob()) call.

 
 

Relacionados problema

2  PHP Crawler para recoger comentarios sobre los artículos  ( Php crawler to collect comments on articles ) 
Tengo código que analiza las páginas web encuentra comentarios y guarda información sobre comentarios en DB. Tengo una matriz donde se almacenan todas las pág...

2  Utilización de apiss de vapor y raspado web  ( Utilization of steam apis and web scraping ) 
alguna información de fondo aquí: Este es un pequeño proyecto divertido que hice utilizando las API de vapor y el raspado web Esta es la primera vez que ...

4  Raspando html usando sopa hermosa  ( Scraping html using beautiful soup ) 
He escrito un script usando una hermosa sopa para raspar un poco de html y hacer algunas cosas y producir HTML de vuelta. Sin embargo, no estoy convencido con...

9  Un raspador web que busca palabras predefinidas en artículos de noticias  ( A web scraper that looks for pre defined words in news articles ) 
Sigo siendo bastante nuevo en Python y Web-rasping, pero un colega me preguntó si podía construir un raspador web que podría ser utilizado por un Think Tank, ...

3  Raspador de noticias de Google para buscar enlaces con historias similares  ( Google news scraper to fetch links with similar stories ) 
El siguiente código lleva una URL o el título a un artículo de noticias existente. busca en Google News usando el título. recoge todos los enlaces de ...

1  Scraper de Python + Selenium para obtener resultados usando la búsqueda inversa  ( Python selenium scraper to grab results using reverse search ) 
He escrito algún código en Python en combinación con Selenium para raspar el resultado poblado de un sitio web después de realizar una búsqueda inversa. Mi ...

6  TRIVAGO Hotels Precio Checker  ( Trivago hotels price checker ) 
He decidido escribir mi primer proyecto en Python. Me gustaría escuchar alguna opinión de usted. Descripción del script: Generar URLS TrivAGO para hote...

5  Cómo obtener información de los países de un sitio web que no está utilizando una verbanización consistente  ( Getting information of countries out of a website that isnt using consistent ve ) 
de este sitio web Necesitaba agarrar la información para cada país e insértelo en una hoja de cálculo de Excel. Mi plan original era usar mi programa y ...

6  BFS / DFS Web Crawler  ( Bfs dfs web crawler ) 
He construido un rastreador web que comienza en una URL de origen y rastrea la web con un método BFS o DFS. Todo está funcionando bien, pero la actuación es h...

11  ¿Es esta la forma en ello a Web-Scrape a una imagen de portada de libros?  ( Is this the clojure way to web scrape a book cover image ) 
¿Hay una manera de escribir esto mejor o más de manera de engaño? Especialmente la última parte con with-open y el let . ¿Debo poner el formulario 9988776...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos