【问题标题】:How to improve this web crawler logic?如何改进这个网络爬虫逻辑?
【发布时间】:2019-03-20 03:48:32
【问题描述】:

我正在开发一个仅使用请求和 bs4 抓取内部链接的网络爬虫。

我在下面有一个粗略的工作版本,但我不确定如何正确处理检查链接是否以前被抓取过。

import re
import time
import requests
import argparse
from bs4 import BeautifulSoup


internal_links = set()

def crawler(new_link):


    html = requests.get(new_link).text 
    soup = BeautifulSoup(html, "html.parser")
    for link in soup.find_all('a', attrs={'href': re.compile("^http://")}):
        if "href" in link.attrs:
            print(link)
            if link.attrs["href"] not in internal_links:
                new_link = link.attrs["href"]
                print(new_link)
                internal_links.add(new_link)
                print("All links found so far, ", internal_links)
                time.sleep(6)
                crawler(new_link)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('url', help='Pass the website url you wish to crawl')
    args = parser.parse_args()

    url = args.url

    #Check full url has been passed otherwise requests will throw error later

    try:
        crawler(url)

    except:
        if url[0:4] != 'http':
            print('Please try again and pass the full url eg http://example.com')



if __name__ == '__main__':
    main()

这些是输出的最后几行:

All links found so far,  {'http://quotes.toscrape.com/tableful', 'http://quotes.toscrape.com', 'http://quotes.toscrape.com/js', 'http://quotes.toscrape.com/scroll', 'http://quotes.toscrape.com/login', 'http://books.toscrape.com', 'http://quotes.toscrape.com/'}
<a href="http://quotes.toscrape.com/search.aspx">ViewState</a>
http://quotes.toscrape.com/search.aspx
All links found so far,  {'http://quotes.toscrape.com/tableful', 'http://quotes.toscrape.com', 'http://quotes.toscrape.com/js', 'http://quotes.toscrape.com/search.aspx', 'http://quotes.toscrape.com/scroll', 'http://quotes.toscrape.com/login', 'http://books.toscrape.com', 'http://quotes.toscrape.com/'}
<a href="http://quotes.toscrape.com/random">Random</a>
http://quotes.toscrape.com/random
All links found so far,  {'http://quotes.toscrape.com/tableful', 'http://quotes.toscrape.com', 'http://quotes.toscrape.com/js', 'http://quotes.toscrape.com/search.aspx', 'http://quotes.toscrape.com/scroll', 'http://quotes.toscrape.com/random', 'http://quotes.toscrape.com/login', 'http://books.toscrape.com', 'http://quotes.toscrape.com/'}

所以它是有效的,但只到了某个点,然后它似乎不再跟随链接。

我确定是因为这条线

for link in soup.find_all('a', attrs={'href': re.compile("^http://")}):

因为那只会找到以 http 开头的链接,而在许多内部页面上,这些链接没有,但是当我这样尝试时

for link in soup.find_all('a')

程序运行非常短暂,然后结束:

http://books.toscrape.com
{'href': 'http://books.toscrape.com'}
http://books.toscrape.com
All links found so far,  {'http://books.toscrape.com'}
index.html
{'href': 'index.html'}
index.html
All links found so far,  {'index.html', 'http://books.toscrape.com'}

【问题讨论】:

    标签: python web-scraping beautifulsoup


    【解决方案1】:

    你可以减少

    for link in soup.find_all('a', attrs={'href': re.compile("^http://")}):
            if "href" in link.attrs:
                print(link)
                if link.attrs["href"] not in internal_links:
                    new_link = link.attrs["href"]
                    print(new_link)
                    internal_links.add(new_link)
    

    links = {link['href'] for link in soup.select("a[href^='http:']")}
    internal_links.update(links)  
    

    这使用抓取仅限定带有 http 协议的标记元素,并使用集合理解来确保没有欺骗。然后它使用任何新链接更新现有集。我不知道足够多的 python 来评论使用 .update 的效率,但我相信它修改了现有的集合而不是创建一个新的集合。这里列出了更多组合集合的方法:How to join two sets in one line without using "|"

    【讨论】:

    • 谢谢,这部分可行,但仍然存在无法找到没有 http 的链接的问题,例如 (about)因此它只是抓取顶级页面而不是更深入。
    • 相对路径是否总是以 /author 开头?
    • 你能提供一个示例网址吗?您只需使用 css 将相对 href url 的选择器添加到现有选择器或语法 soup.select("a[href^='http:'], a[href^='/'] ") 不确定您是否需要用 // 转义最后一个 /
    • 我正在针对 toscrape.com 进行测试,但该站点没有使用内部链接的完整路径,这就是它没有找到所有链接的原因。我已经在一个具有完整 url 路径的站点上尝试过它,现在它可以工作了,理想情况下这对这两种情况都有效,但现在就可以了,谢谢。我会尽快发布我完成的代码并标记答案。
    • 您可以添加相对路径开始,但您需要使用 css 或语法并转义前导 / 考虑它实际上可能需要 \/ 而不是 //。如果你愿意,我可以使用链接进行更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2012-01-14
    • 2011-10-17
    • 1970-01-01
    相关资源
    最近更新 更多