
对外提供两个接口:一个可以提取URL,一个可以增加URL,分别对应图上的1和2。
当要爬取某个网页时,则可以从1接口提取出该网页的URL进行爬取。
有时候爬取的网页内容中会包含别的网页链接,即包含有URL,此时可以把包含的URL提取出来,放入URL管理器,以便后续进行爬取,则可以利用2接口向URL管理器新增URL
图中的3:从URL管理器取出一个URL时,将该URL的状态进行更改,如已爬取、爬取成功、爬取失败等(有多少种状态根据具体需求定义),以防止重复对同一URL进行爬取。
图中的4:把从爬取的网页内容中解析出来的URL放入到URL管理器中前,需要判断URL管理器中是否已存在该URL,已存在就不需要再添加,还是防止对同一URL进行重复爬取。
实现URL管理器有5、6、7三种,
用python中的set集合实现URL管理器,set集合可以实现自动去重,而且可以快速的判断集合中是否已存在某个元素。
已爬取的URL可以用一个set来表示,未爬取的URL用另一个set集合表示。从未爬取的URL集合中取出一个URL进行爬取,并将该URL标记为已爬取URL,放入到已爬取URL的set集合中。当要新增一个URL时,即把新增URL放入未爬取URL集合中,如果未爬取URL集合已存在该URL,则不会重复添加,实现了图中4的逻辑。
如果一个URL有多种状态,如正在爬取中,爬取失败、爬取成功等,可以为每种状态设置一个set集合进行存储。当状态发生转变时,从相应的集合中取出放入到转变后的集合中。
实现逻辑和python内存类似,区别在于Python内存一旦断电就要从头开始执行,但是Redis可以保存中间状态,断电后数据不会消失
可以利用一张urls表进行存储,该表中有两个字段:url 和 url 对应的状态(已爬取、未爬取等)
- class UrlManage:
- """URL 管理器"""
- def __init__(self):
- # 待爬取 URL 集合
- self.new_urls = set()
- # 已爬取 URL 集合
- self.old_urls = set()
-
- def get_url(self):
- """从URL管理器中获取URL进行爬取"""
- if self.has_new_url():
- url = self.new_urls.pop()
- self.old_urls.add(url)
- return url
- return None
-
- def add_new_url(self, url):
- """新增一个 URL"""
- if url is None or len(url) == 0:
- return
- if url in self.old_urls or url in self.new_urls:
- return
- self.new_urls.add(url)
-
- def add_new_urls(self, *urls):
- """批量新增 URL"""
- if urls is None or len(urls) == 0:
- return
- for url in urls:
- self.add_new_url(url)
-
- def has_new_url(self):
- """判断是否还有待爬取 URL"""
- return len(self.new_urls) > 0
-
- # 测试代码
- if __name__ == '__main__':
- url_manage = UrlManage()
- url_manage.add_new_url('url1')
- url_manage.add_new_urls('url1', 'url2', 'url3')
- print('已爬取set:', url_manage.old_urls, '未爬取set:', url_manage.new_urls)
- print('-' * 20)
-
- url = url_manage.get_url()
- print(url)
- print('已爬取set:', url_manage.old_urls, '未爬取set:', url_manage.new_urls)
- print('-' * 20)
-
- url = url_manage.get_url()
- print(url)
- print('已爬取set:', url_manage.old_urls, '未爬取set:', url_manage.new_urls)
- print('-' * 20)
-
- url = url_manage.get_url()
- print(url)
- print('已爬取set:', url_manage.old_urls, '未爬取set:', url_manage.new_urls)
- print('-' * 20)
-
- print(url_manage.has_new_url())
- print('已爬取set:', url_manage.old_urls, '未爬取set:', url_manage.new_urls)