非推奨の(廃止された)文献フォーラム e-bane.net で記事を見つけたいです。一部のフォーラムモジュールが無効になっているため、著者による記事のリストを取得できません。また、このサイトは、Google、Yndexなどの検索エンジンによってインデックス化されていません。
すべての記事を見つける唯一の方法は、サイトの アーカイブページ を開くことです(図1)。次に、特定の年と月を選択する必要があります。 2013年1月 (図1)。そして、各記事(図2)の冒頭にニックネーム-pa4080(図3)が書かれているかどうかを調べる必要があります。しかし、数千の記事があります。
以下のトピックを読んだことがありますが、私のニーズに合ったソリューションはありません。
自分のソリューション を投稿します。しかし、私にとっては興味深いです:このタスクを解決するよりエレガントな方法はありますか?
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 __== '__main__':
main()
requirement.txt
:
aiohttp>=2.3.7
beautifulsoup4>=4.6.0
click>=6.7
スクリプトのpython3バージョンです(Ubuntuのpython3.5でテスト済み17.10)。
使い方:
script.py
であり、パッケージファイルはrequirement.txt
です。pip install -r requirement.txt
を実行します。python3 script.py pa4080
複数のライブラリを使用します。
プログラムをさらに開発するために知っておくべきこと(必要なパッケージのドキュメントを除く):
使い方:
さらに発展させるためのアイデア
これは最もエレガントな答えではありませんが、bash answerを使用するよりも良いと思います。
このタスクを解決するために、主にCLIツールwget
を使用する次のsimplebashスクリプトを作成しました。
#!/bin/bash
TARGET_URL='http://e-bane.net/modules.php?name=Stories_Archive'
KEY_WORDS=('pa4080' 's0ther')
MAP_FILE='url.map'
OUT_FILE='url.list'
get_url_map() {
# Use 'wget' as spider and output the result into a file (and stdout)
wget --spider --force-html -r -l2 "${TARGET_URL}" 2>&1 | grep '^--' | awk '{ print $3 }' | tee -a "$MAP_FILE"
}
filter_url_map() {
# Apply some filters to the $MAP_FILE and keep only the URLs, that contain 'article&sid'
uniq "$MAP_FILE" | grep -v '\.\(css\|js\|png\|gif\|jpg\|txt\)$' | grep 'article&sid' | sort -u > "${MAP_FILE}.uniq"
mv "${MAP_FILE}.uniq" "$MAP_FILE"
printf '\n# -----\nThe number of the pages to be scanned: %s\n' "$(cat "$MAP_FILE" | wc -l)"
}
get_key_urls() {
counter=1
# Do this for each line in the $MAP_FILE
while IFS= read -r URL; do
# For each $KEY_Word in $KEY_WORDS
for KEY_Word in "${KEY_WORDS[@]}"; do
# Check if the $KEY_Word exists within the content of the page, if it is true echo the particular $URL into the $OUT_FILE
if [[ ! -z "$(wget -qO- "${URL}" | grep -io "${KEY_Word}" | head -n1)" ]]; then
echo "${URL}" | tee -a "$OUT_FILE"
printf '%s\t%s\n' "${KEY_Word}" "YES"
fi
done
printf 'Progress: %s\r' "$counter"; ((counter++))
done < "$MAP_FILE"
}
# Call the functions
get_url_map
filter_url_map
get_key_urls
スクリプトには3つの機能があります。
最初の関数get_url_map()
はwget
を--spider
として使用し(ページがあることを確認するだけです)、再帰的な-r
URL $MAP_FILE
を作成します$TARGET_URL
深さレベル-l2
。 (別の例はここにあります: WebサイトをPDFに変換 )。現在の場合、$MAP_FILE
には約20 000個のURLが含まれています。
2番目の関数filter_url_map()
は、$MAP_FILE
の内容を単純化します。この場合、必要なのは文字列article&sid
を含む行(URL)だけで、約3000です。さらにアイデアがあります: テキストファイルの行から特定の単語を削除するには?
3番目の関数get_key_urls()
は、wget -qO-
(コマンドcurl
- examples )を使用して、$MAP_FILE
から各URLのコンテンツを出力し、その中の$KEY_WORDS
のいずれかを見つけてください。特定のURLのコンテンツ内で$KEY_WORDS
のいずれかが見つかった場合、そのURLは$OUT_FILE
に保存されます。
作業プロセス中、スクリプトの出力は次の画像に示すようになります。キーワードが2つある場合は終了までに約63分かかり、1つのキーワードのみが検索される場合は42分です。
この回答 によって提供された @ karel に基づいて my script を再作成しました。スクリプトは、 lynx
の代わりにwget
を使用します。その結果、大幅に高速になります。
現在のバージョンでは、2つの検索キーワードがあり、1つのキーワードのみを検索している場合は8分だけで、15分間同じジョブを実行します。それは @ dan が提供する Python ソリューションよりも高速です。
さらに、lynx
は、非ラテン文字の処理を改善します。
#!/bin/bash
TARGET_URL='http://e-bane.net/modules.php?name=Stories_Archive'
KEY_WORDS=('pa4080') # KEY_WORDS=('Word' 'some short sentence')
MAP_FILE='url.map'
OUT_FILE='url.list'
get_url_map() {
# Use 'lynx' as spider and output the result into a file
lynx -dump "${TARGET_URL}" | awk '/http/{print $2}' | uniq -u > "$MAP_FILE"
while IFS= read -r target_url; do lynx -dump "${target_url}" | awk '/http/{print $2}' | uniq -u >> "${MAP_FILE}.full"; done < "$MAP_FILE"
mv "${MAP_FILE}.full" "$MAP_FILE"
}
filter_url_map() {
# Apply some filters to the $MAP_FILE and keep only the URLs, that contain 'article&sid'
uniq "$MAP_FILE" | grep -v '\.\(css\|js\|png\|gif\|jpg\|txt\)$' | grep 'article&sid' | sort -u > "${MAP_FILE}.uniq"
mv "${MAP_FILE}.uniq" "$MAP_FILE"
printf '\n# -----\nThe number of the pages to be scanned: %s\n' "$(cat "$MAP_FILE" | wc -l)"
}
get_key_urls() {
counter=1
# Do this for each line in the $MAP_FILE
while IFS= read -r URL; do
# For each $KEY_Word in $KEY_WORDS
for KEY_Word in "${KEY_WORDS[@]}"; do
# Check if the $KEY_Word exists within the content of the page, if it is true echo the particular $URL into the $OUT_FILE
if [[ ! -z "$(lynx -dump -nolist "${URL}" | grep -io "${KEY_Word}" | head -n1)" ]]; then
echo "${URL}" | tee -a "$OUT_FILE"
printf '%s\t%s\n' "${KEY_Word}" "YES"
fi
done
printf 'Progress: %s\r' "$counter"; ((counter++))
done < "$MAP_FILE"
}
# Call the functions
get_url_map
filter_url_map
get_key_urls