pa4*_*080 10 command-line scripts wget curl
我想在已弃用(过时)的文学论坛e-bane.net 中找到我的文章。一些论坛模块被禁用,我无法获得他们作者的文章列表。此外,该网站没有被搜索引擎索引,如 Google、Yndex 等。
找到我所有文章的唯一方法是打开站点的存档页面(图 1)。然后我必须选择特定的年份和月份 - 例如2013年1 月(图 1)。然后我必须检查每篇文章(图2)开头是否写着我的昵称-pa4080(图3)。但是有几千篇文章。
我已经阅读了以下几个主题,但没有一个解决方案适合我的需求:
我会发布我自己的解决方案。但对我来说很有趣: 有没有更优雅的方法来解决这个任务?
pa4*_*080 10
为了解决这个任务,我创建了下一个主要使用 CLI 工具的简单bash 脚本wget
。
#!/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
Run Code Online (Sandbox Code Playgroud)
该脚本具有三个功能:
第一个功能get_url_map()
用途wget
的--spider
(这意味着它只会检查网页是否有),并创建循环-r
URL$MAP_FILE
的$TARGET_URL
深度水平-l2
。(可以在此处找到另一个示例:将网站转换为 PDF)。在当前情况下,它$MAP_FILE
包含大约 20 000 个 URL。
第二个函数filter_url_map()
将简化$MAP_FILE
. 在这种情况下,我们只需要包含字符串的行(URL),article&sid
它们大约有 3000 行。更多想法可以在这里找到:如何从文本文件的行中删除特定的单词?
第三个函数get_key_urls()
将使用wget -qO-
(作为命令curl
-示例)从 输出每个 URL 的内容,$MAP_FILE
并尝试在其中查找任何URL $KEY_WORDS
。如果$KEY_WORDS
在任何特定 URL 的内容中建立了任何 ,则该 URL 将保存在$OUT_FILE
.
在工作过程中,脚本的输出看起来就像下一张图片中显示的那样。如果有两个关键字,大约需要 63 分钟,如果只搜索一个关键字,则需要42 分钟。
小智 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 __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
requirement.txt
:
aiohttp>=2.3.7
beautifulsoup4>=4.6.0
click>=6.7
Run Code Online (Sandbox Code Playgroud)
这是脚本的 python3 版本(在 Ubuntu 17.10上的 python3.5 上测试)。
如何使用:
script.py
,包文件是requirement.txt
.pip install -r requirement.txt
。python3 script.py pa4080
它使用几个库:
进一步开发程序需要了解的事情(所需包的文档除外):
怎么运行的:
一些想法,以便进一步发展
这不是最优雅的答案,但我认为它比使用 bash 答案更好。
归档时间: |
|
查看次数: |
1485 次 |
最近记录: |