宽度优先遍历爬虫的python实现

爬虫 宽度优先遍历 python

网上很著名的一本爬虫教程《自己手动写网络爬虫》,该书所有源码是用java编写的,

其中提到了宽度优先遍历算法,闲来无事我把他用python实现了一遍。代码量少了将近一半,呵呵。

宽度优先算法介绍

参考:http://book.51cto.com/art/201012/236668.htm

整个的宽度优先爬虫过程就是从一系列的种子节点开始,把这些网页中的"子节点"(也就是超链接)提取出来,放入队列中依次进行抓取。被处理过的链接需要放 入一张表(通常称为Visited表)中。每次新处理一个链接之前,需要查看这个链接是否已经存在于Visited表中。如果存在,证明链接已经处理过, 跳过,不做处理,否则进行下一步处理。

初始的URL地址是爬虫系统中提供的种子URL(一般在系统的配置文件中指定)。当解析这些种子URL所表示的网页时,会产生新的URL(比如从页面中的<a href= "http://www.admin.com "中提取出http://www.admin.com 这个链接)。然后,进行以下工作:

(1) 把解析出的链接和Visited表中的链接进行比较,若Visited表中不存在此链接,表示其未被访问过。

(2) 把链接放入TODO表中。

(3) 处理完毕后,再次从TODO表中取得一条链接,直接放入Visited表中。

(4) 针对这个链接所表示的网页,继续上述过程。如此循环往复。

表1.3显示了对图1.3所示的页面的爬取过程。

表1.3  网络爬取


TODO 表


Visited 表


A



BCDEF


A


CDEF


A,B


DEF


A,B,C

续表


TODO 表


Visited 表


EF


A,B,C,D


FH


A,B,C,D,E


HG


A,B,C,D,E,F


GI


A,B,C,D,E,F,H


I


A,B,C,D,E,F,H,G



A,B,C,D,E,F,H,G,I

宽度优先遍历是爬虫中使用最广泛的一种爬虫策略,之所以使用宽度优先搜索策略,主要原因有三点:

重要的网页往往离种子比较近,例如我们打开新闻网站的时候往往是最热门的新闻,随着不断的深入冲浪,所看到的网页的重要性越来越低。

万维网的实际深度最多能达到17层,但到达某个网页总存在一条很短的路径。而宽度优先遍历会以最快的速度到达这个网页。

宽度优先有利于多爬虫的合作抓取,多爬虫合作通常先抓取站内链接,抓取的封闭性很强。

宽度优先遍历爬虫的python实现

Python代码

  1. #encoding=utf-8
  2. from BeautifulSoup import BeautifulSoup
  3. import socket
  4. import urllib2
  5. import re
  6. class MyCrawler:
  7. def __init__(self,seeds):
  8. #使用种子初始化url队列
  9. self.linkQuence=linkQuence()
  10. if isinstance(seeds,str):
  11. self.linkQuence.addUnvisitedUrl(seeds)
  12. if isinstance(seeds,list):
  13. for i in seeds:
  14. self.linkQuence.addUnvisitedUrl(i)
  15. print "Add the seeds url \"%s\" to the unvisited url list"%str(self.linkQuence.unVisited)
  16. #抓取过程主函数
  17. def crawling(self,seeds,crawl_count):
  18. #循环条件:待抓取的链接不空且专区的网页不多于crawl_count
  19. while self.linkQuence.unVisitedUrlsEnmpy() is False and self.linkQuence.getVisitedUrlCount()<=crawl_count:
  20. #队头url出队列
  21. visitUrl=self.linkQuence.unVisitedUrlDeQuence()
  22. print "Pop out one url \"%s\" from unvisited url list"%visitUrl
  23. if visitUrl is None or visitUrl=="":
  24. continue
  25. #获取超链接
  26. links=self.getHyperLinks(visitUrl)
  27. print "Get %d new links"%len(links)
  28. #将url放入已访问的url中
  29. self.linkQuence.addVisitedUrl(visitUrl)
  30. print "Visited url count: "+str(self.linkQuence.getVisitedUrlCount())
  31. #未访问的url入列
  32. for link in links:
  33. self.linkQuence.addUnvisitedUrl(link)
  34. print "%d unvisited links:"%len(self.linkQuence.getUnvisitedUrl())
  35. #获取源码中得超链接
  36. def getHyperLinks(self,url):
  37. links=[]
  38. data=self.getPageSource(url)
  39. if data[0]=="200":
  40. soup=BeautifulSoup(data[1])
  41. a=soup.findAll("a",{"href":re.compile(".*")})
  42. for i in a:
  43. if i["href"].find("http://")!=-1:
  44. links.append(i["href"])
  45. return links
  46. #获取网页源码
  47. def getPageSource(self,url,timeout=100,coding=None):
  48. try:
  49. socket.setdefaulttimeout(timeout)
  50. req = urllib2.Request(url)
  51. req.add_header(‘User-agent‘, ‘Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)‘)
  52. response = urllib2.urlopen(req)
  53. if coding is None:
  54. coding= response.headers.getparam("charset")
  55. if coding is None:
  56. page=response.read()
  57. else:
  58. page=response.read()
  59. page=page.decode(coding).encode(‘utf-8‘)
  60. return ["200",page]
  61. except Exception,e:
  62. print str(e)
  63. return [str(e),None]
  64. class linkQuence:
  65. def __init__(self):
  66. #已访问的url集合
  67. self.visted=[]
  68. #待访问的url集合
  69. self.unVisited=[]
  70. #获取访问过的url队列
  71. def getVisitedUrl(self):
  72. return self.visted
  73. #获取未访问的url队列
  74. def getUnvisitedUrl(self):
  75. return self.unVisited
  76. #添加到访问过得url队列中
  77. def addVisitedUrl(self,url):
  78. self.visted.append(url)
  79. #移除访问过得url
  80. def removeVisitedUrl(self,url):
  81. self.visted.remove(url)
  82. #未访问过得url出队列
  83. def unVisitedUrlDeQuence(self):
  84. try:
  85. return self.unVisited.pop()
  86. except:
  87. return None
  88. #保证每个url只被访问一次
  89. def addUnvisitedUrl(self,url):
  90. if url!="" and url not in self.visted and url not in self.unVisited:
  91. self.unVisited.insert(0,url)
  92. #获得已访问的url数目
  93. def getVisitedUrlCount(self):
  94. return len(self.visted)
  95. #获得未访问的url数目
  96. def getUnvistedUrlCount(self):
  97. return len(self.unVisited)
  98. #判断未访问的url队列是否为空
  99. def unVisitedUrlsEnmpy(self):
  100. return len(self.unVisited)==0
  101. def main(seeds,crawl_count):
  102. craw=MyCrawler(seeds)
  103. craw.crawling(seeds,crawl_count)
  104. if __name__=="__main__":
  105. main(["http://www.baidu.com","http://www.google.com.hk"],50)
时间: 2024-11-06 10:22:18

宽度优先遍历爬虫的python实现的相关文章

根据中序和前序序列来构造二叉树,以宽度优先遍历输出

/** * 重建二叉树 :根据给定的前序和中序遍历的结果,构造出树的结构 */ package binaryBree; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; /** * @author Amory.Wang * Question : 重建二叉树 * test example : 普通二叉树 , 特殊二叉树(只有右结点或者只有左结点) ,特殊输入测试 : root=null/输入

网络爬虫——基于JAVA的宽度优先遍历互联网结点

整个的宽度优先爬虫过程就是从一系列的种子节点开始,把这些网页中(种子结点网页)的“子节点” (也就是超链接)提取出来,放入队列中依次进行抓取.被处理过的链接需要放入一张表(通常称 为 Visited 表)中.每次新处理一个链接之前,需要查看这个链接是否已经存在于 Visited 表 中.如果存在,证明链接已经处理过,跳过,不做处理,否则进行下一步处理.实际的过 程如图 1.5 所示. 初始的 URL 地址是爬虫系统中提供的种子 URL(一般在系统的配置文件中指定).当解析这些种子 URL 所表示

BFS - leetcode [宽度优先遍历]

127. Word Ladder int size = q.size(); for(int k = 0; k < size; k++){//for 次数 找到一个erase一个

2.3 基于宽度优先搜索的网页爬虫原理讲解

上一节我们下载并使用了宽度优先的爬虫,这一节我们来具体看一下这个爬虫的原理. 首先,查看HTML.py的源代码. 第一个函数: def get_html(url): try: par = urlparse(url) Default_Header = {'X-Requested-With': 'XMLHttpRequest', 'Referer': par[0] + '://' + par[1], 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64)

实测可用的宽度优先爬虫的实现

参考文献:自己动手写网络爬虫,罗刚,王振东著(我感觉这本书对我还是蛮有用的,爬虫大杂烩啊) 前面写了一篇利用HttpClient来获取单个网页的灌水文,现在希望在此基础之上可以通过一个种子网页能够爬更多的相关网页. 由于互联网的页面上都是相互链接的,可以看成一个超级大的图,每个页面都可以看成是一个节点,而页面中的链接可以看成是图的有向边. 因此能够通过遍历的方式对互联网这个超级大的图进行访问. 突然就把很具体的问题用数据结构抽象的方法给表述出来的了,果然还是抽象牛叉. 图的遍历常可以分为宽度优先

《自己动手写网络爬虫》读书笔记——宽度优先爬虫和带偏好的爬虫

前面只是获取了单个网页内容,在实际中,则使用爬虫程序遍历互联网,把网络中相关的网页全部抓取过来,这也体现了爬虫程序“爬”的概念. 互联网可以看成一个超级大的“图',而每个网页则可以看作是一个”节点“.页面中的链接可以看成是图的”有向边“.因此,可以通过图的遍历的方式对互联网这个”图“进行访问.图的遍历分为宽度优先和深度优先,但深度优先可能会在深度上过于”深”的遍历或者陷入“黑洞”,大多数爬虫都不采用这种方式.此外,在爬取的时候,有时候并不会完全按照宽度优先遍历的方式,而是给待遍历的网页赋予一定的

二叉树遍历,深度有限遍历,广度优先遍历,前序中序后续优先遍历,层次遍历

首先明白两个概念: 1. 深度遍历包括前中后序遍历三种: 2. 广度优先遍历就是层次遍历. PS: 前中后序遍历,如果使用递归遍历,都很简单易理解: 如果使用非递归方式,首先想到的就应该是使用栈结构来控制整个过程,因为递归也是利用栈来实现的: 前中后序遍历的非递归方式中,后序遍历的非递归方式相比较而言,略复杂. 直接上代码: #include "stdlib.h" #include <iostream> #include <stack> #include <

宽度优先算法实践

在下最近在看<编程之美>,由此来实践一些书中有趣的小例子,宽度优先算法便是其中之一.以下内容纯属个人见解,如有错误,请指出~ 注:宽度优先算法是穷举方法的一种. 在下面的实践中,我会用连连看游戏的核心算法(即搜索两个点的最短路径并连接起来),来进行讲述. 连连看是一个2D平面游戏,我使用一个二维数组来保存游戏数据 [ [0,1,2,1], [0,0,0,1], [0,2,1,0], [0,2,0,0], ] 这样子,可以看成一个连连看的模型了,0认为是空的,可以通过,非0值则是障碍物,不可通过

宽度优先搜索

Breadth First Search 宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型.Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想.其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果.换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止. 与树的层序遍历一样 遍历结果为 1 2 3 4 5 6 .....21 22 操作: 根节点入队: wh