script.py
:
#!/usr/bin/python3
from urllib.parse import urljoin
import json
import bs4
import click
import aiohttp
import asyncio
import async_timeout
BASE_URL = 'http://e-bane.net'
async def fetch(session, url):
try:
with async_timeout.timeout(20):
async with session.get(url) as response:
return await response.text()
except asyncio.TimeoutError as e:
print('[{}]{}'.format('timeout error', url))
with async_timeout.timeout(20):
async with session.get(url) as response:
return await response.text()
async def get_result(user):
target_url = 'http://e-bane.net/modules.php?name=Stories_Archive'
res = []
async with aiohttp.ClientSession() as session:
html = await fetch(session, target_url)
html_soup = bs4.BeautifulSoup(html, 'html.parser')
date_module_links = parse_date_module_links(html_soup)
for dm_link in date_module_links:
html = await fetch(session, dm_link)
html_soup = bs4.BeautifulSoup(html, 'html.parser')
thread_links = parse_thread_links(html_soup)
print('[{}]{}'.format(len(thread_links), dm_link))
for t_link in thread_links:
thread_html = await fetch(session, t_link)
t_html_soup = bs4.BeautifulSoup(thread_html, 'html.parser')
if is_article_match(t_html_soup, user):
print('[v]{}'.format(t_link))
# to get main article, uncomment below code
# res.append(get_main_article(t_html_soup))
# code below is used to get thread link
res.append(t_link)
else:
print('[x]{}'.format(t_link))
return res
def parse_date_module_links(page):
a_tags = page.select('ul li a')
hrefs = a_tags = [x.get('href') for x in a_tags]
return [urljoin(BASE_URL, x) for x in hrefs]
def parse_thread_links(page):
a_tags = page.select('table table tr td > a')
hrefs = a_tags = [x.get('href') for x in a_tags]
# filter href with 'file=article'
valid_hrefs = [x for x in hrefs if 'file=article' in x]
return [urljoin(BASE_URL, x) for x in valid_hrefs]
def is_article_match(page, user):
main_article = get_main_article(page)
return main_article.text.startswith(user)
def get_main_article(page):
td_tags = page.select('table table td.row1')
td_tag = td_tags[4]
return td_tag
@click.command()
@click.argument('user')
@click.option('--output-filename', default='out.json', help='Output filename.')
def main(user, output_filename):
loop = asyncio.get_event_loop()
res = loop.run_until_complete(get_result(user))
# if you want to return main article, convert html soup into text
# text_res = [x.text for x in res]
# else just put res on text_res
text_res = res
with open(output_filename, 'w') as f:
json.dump(text_res, f)
if __name__ == '__main__':
main()
requirement.txt
:
aiohttp>=2.3.7
beautifulsoup4>=4.6.0
click>=6.7
Aquí está la versión python3 del script (probado en python3.5 en Ubuntu 17.10 ).
Cómo utilizar:
- Para usarlo ponga ambos códigos en los archivos. Como ejemplo, el archivo de código es
script.py
y el archivo de paquete es requirement.txt
.
- Ejecutar
pip install -r requirement.txt
.
- Ejecute el script como ejemplo
python3 script.py pa4080
Utiliza varias bibliotecas:
Cosas que debe saber para desarrollar el programa más allá (aparte del documento del paquete requerido):
- biblioteca de python: asyncio, json y urllib.parse
- selectores css ( documentos web mdn ), también algunos html. vea también cómo usar el selector css en su navegador, como este artículo
Cómo funciona:
- Primero creo un simple descargador html. Es una versión modificada de la muestra dada en aiohttp doc.
- Después de eso, crea un analizador de línea de comando simple que acepta nombre de usuario y nombre de archivo de salida.
- Cree un analizador para enlaces de hilo y artículo principal. El uso de pdb y la simple manipulación de URL deberían hacer el trabajo.
- Combina la función y coloca el artículo principal en json, para que otro programa pueda procesarlo más tarde.
Alguna idea para que pueda desarrollarse más
- Cree otro subcomando que acepte el enlace del módulo de fecha: se puede hacer separando el método para analizar el módulo de fecha a su propia función y combinarlo con un nuevo subcomando.
- Almacenamiento en caché del enlace del módulo de fecha: cree un archivo json de caché después de obtener el enlace de hilos. para que el programa no tenga que analizar el enlace nuevamente. o incluso simplemente guardar en caché todo el artículo principal del hilo, incluso si no coincide
Esta no es la respuesta más elegante, pero creo que es mejor que usar bash answer.
- Utiliza Python, lo que significa que se puede usar multiplataforma.
- Instalación simple, todo el paquete requerido se puede instalar usando pip
- Se puede desarrollar más, más legible el programa, más fácil se puede desarrollar.
- Hace el mismo trabajo que el script bash solo durante 13 minutos .
sudo apt install python3-bs4 python3-click python3-aiohttp python3-async
, pero no puedo encontrar, ¿de qué paqueteasync_timeout
proviene?Para resolver esta tarea, he creado el siguiente script bash simple que utiliza principalmente la herramienta CLI
wget
.El script tiene tres funciones:
La primera función
get_url_map()
usoswget
como--spider
(lo que significa que se acaba de comprobar que las páginas están allí) y creará recursiva-r
URL$MAP_FILE
del$TARGET_URL
con el nivel de profundidad-l2
. (Otro ejemplo se puede encontrar aquí: Convertir el sitio web a PDF ). En el caso actual,$MAP_FILE
contiene alrededor de 20 000 URL.La segunda función
filter_url_map()
simplificará el contenido de$MAP_FILE
. En este caso, solo necesitamos las líneas (URL) que contienen la cadenaarticle&sid
y son aproximadamente 3000. Aquí se pueden encontrar más ideas: ¿Cómo eliminar palabras particulares de las líneas de un archivo de texto?La tercera función
get_key_urls()
usaráwget -qO-
(como el comandocurl
- ejemplos ) para generar el contenido de cada URL desde el$MAP_FILE
e intentará encontrar cualquiera de$KEY_WORDS
ellos. Si alguno de los$KEY_WORDS
fundamentos se encuentra dentro del contenido de una URL en particular, esa URL se guardará en$OUT_FILE
.Durante el proceso de trabajo, el resultado del script se ve como se muestra en la siguiente imagen. Tarda unos 63 minutos en finalizar si hay dos palabras clave y 42 minutos cuando solo se busca una palabra clave.
fuente
He recreado mi guión basado en la respuesta proporcionada por @karel . Ahora el script usa en
lynx
lugar dewget
. Como resultado, se vuelve significativamente más rápido.La versión actual hace el mismo trabajo durante 15 minutos cuando hay dos palabras clave buscadas y solo 8 minutos si buscamos solo una palabra clave. Eso es más rápido que la solución Python proporcionada por @dan .
Además
lynx
proporciona un mejor manejo de caracteres no latinos.fuente