我正在创建一个程序,该程序在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"])
我的问题是:如何通过页面上的链接从一页移动到下一页?
答案 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 url
:links in that page
不要抓取我们之前抓过的页面。我们可以检查网址是否已经存在
dictionary.keys()
,然后再抓取页面。
当我们找到其中包含target url
的页面时,我们将打印路径并退出。目标仅限于找到从source url
到target 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就是其中之一。