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
Hier ist die Python3-Version des Skripts (getestet unter Python3.5 unter Ubuntu 17.10 ).
Wie benutzt man:
- Um es zu verwenden, legen Sie beide Codes in Dateien. Als Beispiel ist die Codedatei
script.py
und die Paketdatei requirement.txt
.
- Ausführen
pip install -r requirement.txt
.
- Führen Sie das Skript als Beispiel aus
python3 script.py pa4080
Es werden mehrere Bibliotheken verwendet:
Wissenswertes zur Weiterentwicklung des Programms (außer dem Dokument des erforderlichen Pakets):
Wie es funktioniert:
- Zuerst erstelle ich einen einfachen HTML-Downloader. Es handelt sich um eine modifizierte Version aus dem Beispiel in aiohttp doc.
- Danach erstellen Sie einen einfachen Befehlszeilen-Parser, der den Benutzernamen und den Ausgabedateinamen akzeptiert.
- Erstellen Sie einen Parser für Thread-Links und Hauptartikel. Die Verwendung von PDF und einfache URL-Manipulation sollte den Job erledigen.
- Kombinieren Sie die Funktion und stellen Sie den Hauptartikel auf json, damit andere Programme ihn später verarbeiten können.
Eine Idee, damit es weiterentwickelt werden kann
- Erstellen Sie einen weiteren Unterbefehl, der eine Verknüpfung mit dem Datumsmodul akzeptiert: Trennen Sie dazu die Methode, um das Datumsmodul in eine eigene Funktion zu analysieren und mit einem neuen Unterbefehl zu kombinieren.
- Zwischenspeichern des Datumsmodul-Links: Erstellen Sie eine Cache-JSON-Datei, nachdem Sie den Thread-Link erhalten haben. Das Programm muss den Link also nicht erneut analysieren. oder zwischenspeichern Sie einfach den gesamten Thread-Hauptartikel, auch wenn er nicht übereinstimmt
Dies ist nicht die eleganteste Antwort, aber ich denke, es ist besser als die Verwendung einer Bash-Antwort.
- Es verwendet Python, was bedeutet, dass es plattformübergreifend verwendet werden kann.
- Einfache Installation, alle erforderlichen Pakete können mit pip installiert werden
- Es kann weiterentwickelt werden, das Programm ist besser lesbar und es kann einfacher entwickelt werden.
- Es macht den gleichen Job wie das Bash-Skript nur für 13 Minuten .
sudo apt install python3-bs4 python3-click python3-aiohttp python3-async
aber ich kann nicht finden - von welchem Paketasync_timeout
kommt?Um diese Aufgabe zu lösen, habe ich das nächste einfache Bash-Skript erstellt, das hauptsächlich das CLI-Tool verwendet
wget
.Das Skript hat drei Funktionen:
Die erste Funktion
get_url_map()
verwendetwget
as--spider
(was bedeutet, dass nur überprüft wird, ob Seiten vorhanden sind) und erstellt eine rekursive-r
URL$MAP_FILE
der$TARGET_URL
mit Tiefenebene-l2
. (Ein weiteres Beispiel finden Sie hier: Website in PDF konvertieren ). Im aktuellen Fall$MAP_FILE
enthält die ca. 20 000 URLs.Die zweite Funktion
filter_url_map()
vereinfacht den Inhalt der$MAP_FILE
. In diesem Fall benötigen wir nur die Zeilen (URLs), die die Zeichenfolge enthalten,article&sid
und sie sind ungefähr 3000. Weitere Ideen finden Sie hier: Wie entferne ich bestimmte Wörter aus Zeilen einer Textdatei?Die dritte Funktion
get_key_urls()
verwendetwget -qO-
(als Befehlcurl
- Beispiele ), um den Inhalt jeder URL von der auszugeben,$MAP_FILE
und versucht, einen der$KEY_WORDS
darin enthaltenen zu finden. Wenn eine der$KEY_WORDS
URLs im Inhalt einer bestimmten URL enthalten ist, wird diese URL in der gespeichert$OUT_FILE
.Während des Arbeitsprozesses sieht die Ausgabe des Skripts so aus, wie sie im nächsten Bild gezeigt wird. Es dauert ungefähr 63 Minuten, bis zwei Schlüsselwörter vorhanden sind, und 42 Minuten, wenn nur ein Schlüsselwort gesucht wird.
quelle
Ich habe mein Skript basierend auf dieser Antwort von @karel neu erstellt . Jetzt verwendet das Skript
lynx
anstelle vonwget
. Im Ergebnis wird es deutlich schneller.Die aktuelle Version erledigt den gleichen Job 15 Minuten lang, wenn zwei Schlüsselwörter gesucht werden, und nur 8 Minuten, wenn nur ein Schlüsselwort gesucht wird. Das ist schneller als die Python- Lösung von @dan .
lynx
Bietet außerdem eine bessere Handhabung von nicht-lateinischen Zeichen.quelle