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
Voici la version python3 du script (testé sur python3.5 sur Ubuntu 17.10 ).
Comment utiliser:
- Pour l'utiliser, mettez les deux codes dans des fichiers. Par exemple, le fichier de code est
script.py
et le fichier de package est requirement.txt
.
- Courez
pip install -r requirement.txt
.
- Exécutez le script comme exemple
python3 script.py pa4080
Il utilise plusieurs bibliothèques:
Choses à savoir pour développer davantage le programme (autre que le doc du package requis):
- bibliothèque python: asyncio, json et urllib.parse
- sélecteurs css ( mdn web docs ), également certains html. voir aussi comment utiliser le sélecteur css sur votre navigateur tel que cet article
Comment ça fonctionne:
- Je crée d'abord un simple téléchargeur html. Il s'agit d'une version modifiée de l'exemple donné sur aiohttp doc.
- Après cela, créer un analyseur de ligne de commande simple qui accepte le nom d'utilisateur et le nom de fichier de sortie.
- Créez un analyseur pour les liens de discussion et l'article principal. L'utilisation de pdb et d'une simple manipulation d'url devrait faire l'affaire.
- Combinez la fonction et mettez l'article principal sur json, afin qu'un autre programme puisse le traiter plus tard.
Une idée pour qu'elle puisse être développée davantage
- Créez une autre sous-commande qui accepte le lien du module de date: cela peut être fait en séparant la méthode pour analyser le module de date à sa propre fonction et le combiner avec la nouvelle sous-commande.
- Mise en cache du lien du module de date: créer un fichier json de cache après avoir obtenu le lien des threads. afin que le programme n'ait pas à analyser à nouveau le lien. ou même simplement mettre en cache l'intégralité de l'article principal du fil même s'il ne correspond pas
Ce n'est pas la réponse la plus élégante, mais je pense que c'est mieux que d'utiliser la réponse bash.
- Il utilise Python, ce qui signifie qu'il peut être utilisé sur plusieurs plates-formes.
- Installation simple, tous les packages requis peuvent être installés à l'aide de pip
- Il peut être développé davantage, plus lisible par le programme, plus facile à développer.
- Il ne fait le même travail que le script bash que pendant 13 minutes .
sudo apt install python3-bs4 python3-click python3-aiohttp python3-async
mais je ne trouve pas - de quel paquetasync_timeout
vient-il?