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?