使用python查找链接页面到目标页面

问题描述 投票:3回答:2

我正在创建一个程序,在Wikipedia上给出起始页面和目标页面,通过每页上的超链接从起始页面导航到目标页面。例如,如果我们有凝视页面A和目标页面B,并且A链接到C,它链接到B,我们可以通过A - > C - > B从A到B.

我尝试过使用漂亮的汤,但我不熟悉网页抓取。到目前为止,我已经从页面中提取了html并对链接进行了排序。我到目前为止的代码是这样的:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

html = urlopen("https://en.wikipedia.org/wiki/Web_Bot")
bs = BeautifulSoup(html, "lxml")
links = bs.find("div", {"id": "bodyContent"}).findAll("a", 
href=re.compile("^(/wiki/)((?!:).)*$"))

for link in links:
    if "href" in link.attrs:
        print(link.attrs["href"])

我的问题是:如何通过页面上的链接从一个页面移动到另一个页面?

python web-scraping beautifulsoup scrapy
2个回答
2
投票

一般来说,你想要实现的并不是一项微不足道的任务。还有几个需要解决的问题。

问题1:跟踪您已访问过的所有链接以及您尚未访问的链接

问题2:知道何时停止。如果您抓取的网站非常小,那么您可以希望在一段时间后您只需找到所有可能的链接,您的抓取就会结束。

问题3:根据与哪个页面链接的知识查找路径。现在可能的解决方案:

问题1.解决方案A:使用队列和集合。在每个步骤中,将当前页面链接放入一组访问链接,从页面获取链接,检查它们中是否已存在一组访问链接,添加新链接到队列。然后从队列中选择下一个链接进行访问。非常简单的方法,特别是如果你的爬虫可以花时间。这将按顺序执行所有操作。一页接一页。

问题1.解决方案B:花1-2小时阅读Scrapy并尝试使用Scrapy实现爬行。它将为您执行多线程处理,并提供查找链接的工具(类似于您在BeautifulSoup中的操作方式)。优点:已经实现了许多功能,例如导出为CSV,JSON以进行进一步处理,记录,抓取统计信息等。

问题2.解决方案A.这取决于。如果您正在寻找任何特定路径,那么您可以在到达目标页面后立即停止,然后您可以重建从A到B的路径。

问题2.解决方案B.如果您正在寻找最短路径或能力为任何给定的A和B找到A和B之间的路径,那么您可以通过跳数限制您的爬行。假设你从页面A开始,它有到B1,B2和B3的链接。您访问它们并给它们序号1.这些B页面链接到C1,C2,C3,C4,C5 - 您访问这些页面并给它们序号2.您继续直到达到序号X,这意味着那些页面是X跳远你开始页面。这将确保您限制抓取时间。

问题3.解决方案A.当您从A页转到B1,B2,B3页面时,您“附加一个”A“的”parsel“。这意味着可以从页面A访问这些页面。您访问的每个新页面还必须保留有关可以从哪里访问的信息。然后使用DFS或BFS算法在该组链接页中查找路径。

问题3.解决方案B.您不必保留对前一页的引用,而是维护一个列表。如果您从A访问B,则您的B链接将以“A”作为其路径。但是如果你从B访问C,你将B添加到现有路径,C将包含“A-> B”,依此类推。这意味着最终每个链接都有一条从A到该链接的路径。如果您对从A到任何其他页面的任何路径感兴趣,请运行良好。

问题3.解决方案C.对于每个页面,当您从中提取所有链接时,您将构建一个地图,其中您的页面是关键,其中包含的链接列表是值。它与方法A相反,而不是孩子有父页面的引用,你有父页面列出其子页面。在这种情况下,您也可以使用DFS或WFS算法查找任意两个页面之间的路径。


2
投票

废弃像维基百科这样的“巨大”网站有“巨大”的资源需求。我个人并不认为这是一项可以由资源有限的人完成的任务,或者这是一个可以在堆栈溢出答案的字数限制内明确回答的问题,即使知道如何。话虽这么说,我的答案中的以下方法可能适用于有几百页的较小网站。

做法:

  • 定义源页面和目标页面。
  • 从源页面开始抓取并递归抓取每个链接,直到我们之前没有抓取的结束页面中没有链接。
  • 将每个已抓取的页面保存到字典中,例如master_link_dictkey:value对作为crawled page urllinks in that page
  • 不要抓取我们之前抓取过的网页。我们可以在抓取页面之前检查dictionary.keys()中是否已有网址。
  • 当我们找到一个包含target url的页面时,我们打印出这条线索并退出。目标仅限于寻找从source urltarget url的路径

码:

import requests
from bs4 import BeautifulSoup
import re
import pprint
source_page='/wiki/Web_Bot'
target_page='/wiki/Computer_Sciences_Corporation'
master_link_dict={}
#initialize trail with target
trail_reverse=[target_page]
def get_links(url):
    html=requests.get('https://en.wikipedia.org'+url)
    soup = BeautifulSoup(html.text, "html.parser")
    links = soup.find("div", {"id": "bodyContent"}).findAll("a", href=re.compile("^(/wiki/)((?!:).)*$"))
    hrefs=[x['href'] for x in links]
    return hrefs

def recursive_crawl(url):
    #don't crawl again if the page has already been crawled
    if url in master_link_dict.keys():
        return
    #get all urls in the current page
    url_list=get_links(url)
    #store as page:[list of urls] in the master dict
    master_link_dict[url]=url_list

    #if target page is found print trail
    if target_page in url_list:
        find_trail(url)

    #crawl all urls of curret page
    for item in url_list:
        recursive_crawl(item)

def find_trail(url):
    #append current url to trail reverse
    trail_reverse.append(url)
    #if current url is the source url print trail and exit
    if url is source_page:
        print('->'.join(trail_reverse[::-1]))
        exit()
    #if current url is in a page, get trail of that page
    for page,url_list in master_link_dict.items():
        if url in url_list:
            find_trail(page)

recursive_crawl(source_page)

输出:

/wiki/Web_Bot->/wiki/Internet_bot->/wiki/Automated_bot->/wiki/Computer_science->/wiki/Computer_Sciences_Corporation

备注和免责声明:

  • 答案当然非常简单,并没有考虑到许多边缘情况。例如。如果两个页面A和B之间没有路径怎么办?
  • 我尽我所能回答,但可能有更好的方法。
  • 我没有随机选择target url。我搜索了许多3-6页的网址进行测试。代码中的url就是其中之一。
© www.soinside.com 2019 - 2024. All rights reserved.