使用python

时间:2019-03-11 17:37:44

标签: python web-scraping beautifulsoup scrapy

我正在创建一个程序,该程序在Wikipedia上有一个起始页面和一个目标页面,并通过每个页面上的超链接从起始页面导航到目标页面。例如,如果我们有凝视页A和目标页B,并且A链接到C,而B链接到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"])

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

2 个答案:

答案 0 :(得分: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算法来查找任意两个页面之间的路径。

答案 1 :(得分:2)

像Wikipedia这样的“巨大” 网站报废了“巨大” 资源需求。我个人不认为这是资源有限的个人可以完成的任务,或者即使在已知的情况下,也可以在堆栈溢出答案的字数限制内明确地回答这个问题。话虽如此,我回答中的以下方法可能在具有数百页的较小站点上起作用。

方法:

  • 定义源页面和目标页面。

  • 从源页面开始爬网,并递归地爬网每个链接,直到结束页面中没有我们以前没有爬过的链接。

  • 将每个抓取的页面保存到字典中,说master_link_dict,其中key:value对为crawled page urllinks in that page

  • 不要抓取我们之前抓过的页面。我们可以检查网址是否已经存在 dictionary.keys(),然后再抓取页面。

  • 当我们找到其中包含target url的页面时,我们将打印路径并退出。目标仅限于找到从source urltarget url

  • a 路径

代码:

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就是其中之一。