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
Ось версія сценарію python3 (протестована на python3.5 на Ubuntu 17.10 ).
Як користуватись:
- Для його використання покладіть обидва коди у файли. Наприклад, файл коду
script.py
та файл пакета requirement.txt
.
- Біжи
pip install -r requirement.txt
.
- Запустіть сценарій як приклад
python3 script.py pa4080
Тут використовується кілька бібліотек:
Що потрібно знати для подальшої розробки програми (крім документа необхідного пакету):
- бібліотека пітона: asyncio, json та urllib.parse
- css-селектори ( mdn web docs ), також деякі html. дивіться також, як використовувати селектор css у своєму браузері, наприклад, у цій статті
Як це працює:
- Спочатку я створю простий завантажувач html. Це модифікована версія із зразка, поданого на doc. Aiohttp.
- Після цього створюється простий синтаксичний аналізатор командного рядка, який приймає ім'я користувача та вихідне ім'я файлу.
- Створіть аналізатор посилань на потоки та основну статтю. Використання pdb та простих маніпуляцій з URL-адресою повинно зробити цю роботу.
- Поєднайте функцію та поставте головну статтю на json, щоб інша програма змогла її обробити пізніше.
Якась ідея, щоб вона могла розвиватися далі
- Створіть ще одну підкоманду, яка приймає посилання модуля дати: це можна зробити, розділивши метод розбору модуля дати на власну функцію та поєднати його з новою підкомандою.
- Кешування посилання модуля дати: створити файл кеша json після отримання посилання. тому програмі не доведеться знову розбирати посилання. або навіть просто кешувати всю основну статтю теми, навіть якщо вона не відповідає
Це не найелегантніша відповідь, але я вважаю, що це краще, ніж використовувати баш-відповідь.
- Він використовує Python, що означає, що він може використовуватися крос-платформою.
- Проста установка, весь необхідний пакет можна встановити за допомогою pip
- Її можна розвивати далі, програму читати, легше її розробляти.
- Він виконує ту саму роботу, що і сценарій bash лише протягом 13 хвилин .
sudo apt install python3-bs4 python3-click python3-aiohttp python3-async
але я не можу знайти - з якого пакетаasync_timeout
походить?