示例#1
0
文件: Koala.py 项目: figot/pykoala
def get_url_html(url):
	'''
	获取url的html超文本

	@param url: url地址
	@type url: 字符串

	@return: 成功则返回html,失败则触发异常
	@rtype: 字符串
	'''
	# 自定义header
	customHeader = dict()
	customHeader['User-Agent'] = Config.KOALA_USER_AGENT

	# 网络出错重试机制
	retryTimes = 0
	while True:
		try:
			# 先发送head做检测工作
			rsp = requests.head(url, headers = customHeader)
			if not rsp.ok:
				rsp.raise_for_status()
			if not rsp.headers['content-type'].startswith('text/html'):
				raise TypeError('Specified url do not return HTML file')

			rsp = requests.get(url, headers = customHeader)
			return Common.to_unicode(rsp.content)
		except requests.exceptions.RequestException as e:
			Common.write_stderr(repr(e))
			if retryTimes < Config.NETWORK_ERROR_MAX_RETRY_TIMES:
				retryTimes += 1
				time.sleep(Config.NETWORK_ERROR_WAIT_SECOND)
			else:
				raise
示例#2
0
文件: Koala.py 项目: figot/pykoala
	def __init__(self, webSiteURL, entryFilter = None, yieldFilter = None, identifier = None, enableStatusSupport = False):
		'''
		@param webSiteURL: 网站url地址
		@type webSiteURL: 字符串
		@param entryFilter: 入口过滤器,指定了爬虫可以进入哪些url。定义为字典,详情如下:
							['Type']
								'allow'	允许模式,只要满足过滤项目表中的任意一项即允许
								'deny'	排除模式,只要满足过滤项目表中的任意一项即排除
							['List']
								过滤项目列表,每一项均为正则表达式,字符串
		@type entryFilter: 字典
		@param yieldFilter: 生成过滤器,指定了爬虫要生成哪些url。定义为字典,详情如下:
							['Type']
								'allow'	允许模式,只要满足过滤项目表中的任意一项即允许
								'deny'	排除模式,只要满足过滤项目表中的任意一项即排除
							['List']
								过滤项目列表,每一项均为正则表达式,字符串
		@type yieldFilter: 字典
		@param identifier: 爬虫的id,用来标识爬虫
		@type identifier: 字符串
		@param enableStatusSupport: 是否启用状态支持,默认不启用
		@type enableStatusSupport: 布尔值
		'''
		if not webSiteURL:
			raise ValueError('You must specified "webSiteURL" parameter in constructor')

		webSiteURL = Common.to_unicode(webSiteURL)

		# 如果url没有协议前缀,则使用默认协议前缀
		webSiteURL = ensure_url_default_scheme(webSiteURL)

		self.domain 		= get_domain(webSiteURL)
		self.webSiteURL 	= webSiteURL
		self.entryFilter 	= entryFilter
		self.yieldFilter 	= yieldFilter

		# 如果没有指定id,则生成uuid
		if not identifier:
			self.identifier = str(uuid.uuid1())
		else:
			self.identifier = identifier

		# 是否启用状态支持的标记
		if not enableStatusSupport:
			self.koalaStatus = None
		else:
			self.koalaStatus = KoalaStatus(Common.hash(self.webSiteURL))

		# 记录访问过的页面
		self.visitedEntriesHash = set()
示例#3
0
文件: Koala.py 项目: figot/pykoala
	def __crawl_proc(self, entryURL, maxDepth):
		'''
		爬行的执行过程

		@param entryURL: 爬虫的入口url
		@type entryURL: 字符串
		@param maxDepth: 最大抓取深度
		@type maxDepth: 整数

		@return: 满足过滤条件的url
		@rtype: 字符串
		'''
		# 如果达到最大深度则返回
		if maxDepth <= 0:
			return

		# 解析出页面中所有的链接
		try:
			source = get_url_html(entryURL)
			soup = BeautifulSoup(source, Config.DEFAULT_HTML_PARSER)
		except Exception as e:
			Common.write_stderr(repr(e))
			return
		links = list()
		for a in soup.find_all('a'):
			try:
				links.append(a['href'].encode(Common.UTF8_CHARSET_NAME))
			except KeyError as e:
				Common.write_stderr(repr(e))
		links = [Common.to_unicode(l) for l in links]

		# 生成符合规则的链接,并记录符合规则的子页面
		nextEntries = list()
		for link in links:
			url = urlparse.urljoin(entryURL, link)
			if self.__global_filter(entryURL, url):
				if self.__yield_filter(url):
					yield url
				if self.__entry_filter(url):
					nextEntries.append(url)

		# 执行到此处代表一个(子)页面(EntryURL)处理完成

		# 需要记录到已处理页面集合中。处于性能考虑,记录url的hash值而非url本身
		self.visitedEntriesHash.add(Common.hash(entryURL))

		# 如果启用状态支持,则同步删除数据库中对应的NextEntry数据(如果有的话)
		if self.koalaStatus:
			self.koalaStatus.remove_next_entry([entryURL])

		# 如果即将达到最大深度,处于性能考虑,不再进入子页面
		if maxDepth - 1 <= 0:
			return
		else:
			# 准备进入子页面之前,同步更新状态
			if self.koalaStatus:
				self.koalaStatus.add_next_entry(nextEntries)

			# 广度优先抓取
			for nextEntryURL in nextEntries:
				if Common.hash(nextEntryURL) not in self.visitedEntriesHash:
					for i in self.__crawl_proc(nextEntryURL, maxDepth - 1):
						yield i