看不到无限循环
Can't see infinite loop
我正在尝试编写一个网络爬虫,但我被卡住了,因为我在我的代码中看不到无限循环。
class Crawler(object):
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.start_url = url
self.start_parsed = urllib3.util.parse_url(url)
self.query = re.compile(query, re.IGNORECASE)
self.dir = dir
self.__horizon = set()
self.log = []
self.__horizon.add(url)
self.log.append(url)
print("initializing crawler....")
print(locals())
def start(self, depth= 5, url = '/'):
print(url, depth)
self.log.append(url)
if depth > 0:
pool = urllib3.PoolManager()
data = pool.request("GET", self.start_url if url == '/' else url).data.decode('utf-8')
valid_list = []
self.add_horizon(parser_soup.get_links(data), valid_list)
if re.search(self.query, parser_soup.get_text(data)):
self.output(data)
for u in valid_list:
self.start(depth = (depth-1), url = u)
def output(self, data):
with open(os.path.join(self.dir, get_top_domain(self.start_parsed.host) + '.' + str(time.time()) + '.html'), 'w+') as f:
f.write(data)
def add_horizon(self, url_list, valid_list = []):
for url in url_list:
if get_top_domain(url) == get_top_domain(self.start_parsed.host) \
and (not str(url) in self.log or not str(url) in self.__horizon):
valid_list.append(str(url))
self.__horizon.update(valid_list)
它永远运行。我应该如何确保消除重复链接?
在您的抓取工具中添加 visited
属性。
from collections import defaultdict
class Crawler:
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.visited = defaultdict(bool)
# Rest of code...
def start(self, depth= 5, url = '/'):
if self.visited[url]:
return True
self.visited[url] = True
# Rest of code...
老实说,我也看不到无限循环。如果您发布了一些输出,将会有所帮助。
编辑:请注意,在上面的回答中,我写道使用 defaultdict
是错误的解决方案。我的意思是说使用 list 是错误的解决方案!
编辑 2:@Jona Christopher Sahnwald 提出的观点比我的更有效(请参阅他在 OP 问题下的评论)。在 class 中添加 max_visit
和 current_visit
属性 可能会更有效率(设置为 1000 左右)。从 0 的 current_visit
开始,每次访问站点时,递增 current_visit
。当 current_visit
大于 max_visit
时,中止抓取。请注意,与其使用递归来递归访问过的网站,不如实施某种堆栈,这样您就可以 pause/resume 抓取而不是中止。像这样:
from collections import defaultdict
class Crawler:
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.visited = defaultdict(bool)
self.current_visit = 0
self.max_visit = 1000
self.to_visit = []
# Rest of code...
def start(self, depth=5, url = '/'):
self.to_visit.append((url, 1))
while len(self.to_visit) > 0:
url, current_depth = self.to_visit.pop()
if current_depth > depth:
continue
elif visited[url]:
continue
elif self.current_visited > self.max_visited:
break
self.current_visited += 1
visited[url] = True
# Code that does something for each page (like download it, etc)
# Code that finds links on page...
for link in links_on_page:
self.to_visit.append((link, current_depth + 1))
这样,您可以在 current_visit
超过 max_visit
时暂停抓取,从而分批抓取 max_visit
.
改编自 Giogian 的代码:
class Crawler(object):
def __init__(self, url, query, dir=os.path.dirname(__file__)):
self.visited = set()
# Rest of code...
def start(self, depth=5, url='/'):
if url in self.visited:
return True
self.visited.add(url)
defaultdict
是一个具有默认值的字典,如果索引不存在则使用该默认值。然而,这是错误的解决方案。如我的代码所示,集合会更高效、更优雅。
一组使用 O(1) 时间 - 与@Giorgian 的回答一样快。
使用Ctrl-C
可以在程序处于无限循环时中断它。这将打印一个 Traceback,显示程序中断时正在执行的命令。这样做几次,您应该清楚它发生的位置。或者,使用调试器并在它处于无限循环时暂停,并使用 "step" 功能 运行 下一行执行,以便您可以跟踪程序的执行。 PyCharm 是一个包含调试器的出色编辑器。它有很好的自动补全功能,而且各方面都很好。免费,快来看看吧。
我正在尝试编写一个网络爬虫,但我被卡住了,因为我在我的代码中看不到无限循环。
class Crawler(object):
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.start_url = url
self.start_parsed = urllib3.util.parse_url(url)
self.query = re.compile(query, re.IGNORECASE)
self.dir = dir
self.__horizon = set()
self.log = []
self.__horizon.add(url)
self.log.append(url)
print("initializing crawler....")
print(locals())
def start(self, depth= 5, url = '/'):
print(url, depth)
self.log.append(url)
if depth > 0:
pool = urllib3.PoolManager()
data = pool.request("GET", self.start_url if url == '/' else url).data.decode('utf-8')
valid_list = []
self.add_horizon(parser_soup.get_links(data), valid_list)
if re.search(self.query, parser_soup.get_text(data)):
self.output(data)
for u in valid_list:
self.start(depth = (depth-1), url = u)
def output(self, data):
with open(os.path.join(self.dir, get_top_domain(self.start_parsed.host) + '.' + str(time.time()) + '.html'), 'w+') as f:
f.write(data)
def add_horizon(self, url_list, valid_list = []):
for url in url_list:
if get_top_domain(url) == get_top_domain(self.start_parsed.host) \
and (not str(url) in self.log or not str(url) in self.__horizon):
valid_list.append(str(url))
self.__horizon.update(valid_list)
它永远运行。我应该如何确保消除重复链接?
在您的抓取工具中添加 visited
属性。
from collections import defaultdict
class Crawler:
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.visited = defaultdict(bool)
# Rest of code...
def start(self, depth= 5, url = '/'):
if self.visited[url]:
return True
self.visited[url] = True
# Rest of code...
老实说,我也看不到无限循环。如果您发布了一些输出,将会有所帮助。
编辑:请注意,在上面的回答中,我写道使用 defaultdict
是错误的解决方案。我的意思是说使用 list 是错误的解决方案!
编辑 2:@Jona Christopher Sahnwald 提出的观点比我的更有效(请参阅他在 OP 问题下的评论)。在 class 中添加 max_visit
和 current_visit
属性 可能会更有效率(设置为 1000 左右)。从 0 的 current_visit
开始,每次访问站点时,递增 current_visit
。当 current_visit
大于 max_visit
时,中止抓取。请注意,与其使用递归来递归访问过的网站,不如实施某种堆栈,这样您就可以 pause/resume 抓取而不是中止。像这样:
from collections import defaultdict
class Crawler:
def __init__(self, url, query, dir = os.path.dirname(__file__)):
self.visited = defaultdict(bool)
self.current_visit = 0
self.max_visit = 1000
self.to_visit = []
# Rest of code...
def start(self, depth=5, url = '/'):
self.to_visit.append((url, 1))
while len(self.to_visit) > 0:
url, current_depth = self.to_visit.pop()
if current_depth > depth:
continue
elif visited[url]:
continue
elif self.current_visited > self.max_visited:
break
self.current_visited += 1
visited[url] = True
# Code that does something for each page (like download it, etc)
# Code that finds links on page...
for link in links_on_page:
self.to_visit.append((link, current_depth + 1))
这样,您可以在 current_visit
超过 max_visit
时暂停抓取,从而分批抓取 max_visit
.
改编自 Giogian 的代码:
class Crawler(object):
def __init__(self, url, query, dir=os.path.dirname(__file__)):
self.visited = set()
# Rest of code...
def start(self, depth=5, url='/'):
if url in self.visited:
return True
self.visited.add(url)
defaultdict
是一个具有默认值的字典,如果索引不存在则使用该默认值。然而,这是错误的解决方案。如我的代码所示,集合会更高效、更优雅。
一组使用 O(1) 时间 - 与@Giorgian 的回答一样快。
使用Ctrl-C
可以在程序处于无限循环时中断它。这将打印一个 Traceback,显示程序中断时正在执行的命令。这样做几次,您应该清楚它发生的位置。或者,使用调试器并在它处于无限循环时暂停,并使用 "step" 功能 运行 下一行执行,以便您可以跟踪程序的执行。 PyCharm 是一个包含调试器的出色编辑器。它有很好的自动补全功能,而且各方面都很好。免费,快来看看吧。