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
Oto wersja skryptu python3 (przetestowana na python3.5 na Ubuntu 17.10 ).
Jak używać:
- Aby go użyć, umieść oba kody w plikach. Przykładowo plik kodu to
script.py
plik pakietu requirement.txt
.
- Uruchom
pip install -r requirement.txt
.
- Uruchom skrypt jako przykład
python3 script.py pa4080
Wykorzystuje kilka bibliotek:
Co należy wiedzieć, aby dalej rozwijać program (inny niż dokument wymaganego pakietu):
- biblioteka python: asyncio, json i urllib.parse
- selektory css ( mdn web docs ), także niektóre pliki HTML. Zobacz także, jak korzystać z selektora css w przeglądarce, na przykład w tym artykule
Jak to działa:
- Najpierw tworzę prosty downloader HTML. Jest to zmodyfikowana wersja z próbki podanej na aiohttp doc.
- Po utworzeniu prostego parsera wiersza poleceń, który akceptuje nazwę użytkownika i wyjściową nazwę pliku.
- Utwórz parser dla linków wątków i głównego artykułu. Używanie pdb i prostych manipulacji adresami URL powinno wystarczyć.
- Połącz funkcję i umieść główny artykuł w json, aby inny program mógł go przetworzyć później.
Trochę pomysłu, dzięki czemu można go dalej rozwijać
- Utwórz kolejną komendę, która akceptuje łącze do modułu daty: można to zrobić, oddzielając metodę parsowania modułu daty do jego własnej funkcji i łącząc go z nową komendą.
- Buforowanie łącza modułu daty: utwórz plik json pamięci podręcznej po uzyskaniu łącza wątków. więc program nie musi ponownie analizować łącza. lub nawet po prostu buforuj cały główny artykuł wątku, nawet jeśli nie pasuje
To nie jest najbardziej elegancka odpowiedź, ale myślę, że jest lepsza niż użycie bash.
- Korzysta z Pythona, co oznacza, że można go używać na różnych platformach.
- Prosta instalacja, wszystkie wymagane pakiety można zainstalować za pomocą pip
- Można go dalej rozwijać, bardziej czytelny program, łatwiej można go rozwijać.
- Działa tak samo jak skrypt bash tylko przez 13 minut .
sudo apt install python3-bs4 python3-click python3-aiohttp python3-async
ale nie mogę znaleźć - z którego pakietuasync_timeout
pochodzi?