python轻量级爬虫的编写

Posted GuityCrown

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python轻量级爬虫的编写相关的知识,希望对你有一定的参考价值。

嗯...今天来分享一下如何使用python编写一个简单的网络爬虫。说到爬虫,这简直就是广大懒惰的程序员和宅男们的福音啊,一次编写,想要啥资源就能爬啥资源,高至各种学习资源,论文资料,低至各种图片小视频(...)等等...嗯...这里讲解了如何搭建一个简单爬虫的框架之后,会基于该框架编写一个栗子,该栗子代码会从python的百科页面开始,爬取各种百科页面信息并记录下来。

注意,这里的标题是《*轻量级爬虫*》,之所以说是轻量级,是因为这里只涉及到静态网页的解析,至于AJAX异步加载,JS脚本什么的并不涉及。

先来代码链接~~~

python爬虫内存版

python爬虫MySQL版

噢,对了,这个爬虫有两个版本,一个是mysql版,一个是内存板。有啥区别呢,就是前者是使用MySQL数据库存储已经访问过的URL的,后者则使用内存。前者的好处是,多次运行相互独立,不会重复爬取相同的URL,而后者不一样,每一次运行都会从相同的URL出发,重复爬取相同的URL,那是因为前者是持久化存储,而后者不是。一旦后者的程序关掉,所有已经被访问过的URL记录就会清空。但是,前者也有一个缺点,那就是运行速度比较慢...具体怎么样,大家把代码下载下来跑一下就清楚了。下面讲述的是内存存储版的~~~

1. python爬虫框架

在编写代码之前,我们应该先确定一个良好的代码框架,这也是一个优秀的程序员应有的习惯(咳咳...我还不算一个优秀的程序员...以后会是的...)。这里,我将会讲述一个简单爬虫的框架。

一个最基本的爬虫应该由一下4部分组成:URL调度器,网页下载器,网页解析器,爬取信息输出器。以下是它们相互协调工作的流程图。

假设这四大功能块都以上图中命名方式命名,那么根据上述流程图,我们可以编写爬虫的主程序如下(为了测试方便,下面代码限制了爬取的URL数量为10个):

# 爬虫主程序
class SpiderMain(object):
	def __init__(self):
		self.url_manager=UrlManager()
		self.downloader=htmlDownloader()
		self.parser=HtmlParser()
		self.outputer=HtmlOutputer()

	def craw(self, url):
		num=0
		self.url_manager.add_new_url(url)
		while self.url_manager.has_new_url() and num < 10:
			url = self.url_manager.get_new_url() 
			print url
			# 下载网页内容
			content=self.downloader.download(url)
			if content is None:
				print "Craw failed"
				continue
			#解析网页数据
			data = self.parser.parse(url, content)
			if data is None:
				print "Craw failed"
				continue
			new_urls = data[0]
			new_data = data[1]
			# 收集解析后爬取的数据
			self.url_manager.add_new_urls(new_urls)
			self.outputer.collect(new_data)

			num+=1

		self.outputer.output()

1) URL调度器

URL调度器负责URL的处理,主要是对将未访问过的URL提供给网页下载器进行访问及下载,将已经访问过的URL屏蔽,防止程序洪福爬取相同的页面,提高效率。它不停地给网页下载器提供新的URL并随之屏蔽掉,如此往复,直到没有新的URL或者达到了爬取数目限制。假设URL调度器是一个类UrlManager,那么我们可以编写如下代码:

# URL调度器
class UrlManager(object):
	def __init__(self):
		self.new_url=set()
		self.old_url=set()

	def add_new_url(self,url):
		if url not in self.new_url and url not in self.old_url:
			self.new_url.add(url)

	def add_new_urls(self,urls):
		if urls is None or len(urls) == 0:
			return
		for url in urls:
			self.add_new_url(url)

	def has_new_url(self):
		return len(self.new_url)!=0

	def get_new_url(self):
		url = self.new_url.pop()
		self.old_url.add(url)
		return url
简单的解析一下,UrlManager提供两个接口,让主程序可以给它添加一个或多个新的URL,也可以从中获取一个需要访问的URL,一旦获取了一个URL之后,UrlManager会将该URL添加到old_url集合中将其屏蔽。

2) 网页下载器

这个很简单,我们使用urllib2提供的接口就可以获取一个指定URL的内容。代码如下:

# 下载网页内容
class HtmlDownloader(object):
	def download(self,url):
		if url is None:
			return None
		try:
			response = urllib2.urlopen(url)
		except urllib2.URLError:
			return None
		except urllib2.HTTPError:
			return None
		if response.getcode() != 200:
			return None
		return response.read()
这里只需要注意使用try-except来处理异常即可,防止程序崩溃。

3) 网页解析器

我们使用BeautifulSoap解析网页,BeautifulSoup是一个专门用于解析网页并得到DOM树的一个python第三方库,下面简单地说一下如何使用BeautifulSoap解析网页。我们以百度百科为栗。

首先,我们打开http://baike.baidu.com/view/21087.htm这个页面,并右键查看元素。我们先来看看标题的html代码。

我们可以看到,标题Python的html代码为

...
<dd class="lemmaWgt-lemmaTitle-title">
<h1>Python</h1>
...
根据这些标签我们就可以使用BeautifulSoap定位这个标题了。具体怎么写下面说。

BeautifulSoap提供了find和find_all方法来寻找一个或多个指定节点。以上面的标题为栗,我们可以编写python代码如下。

soup = BeautifulSoup(content,'html.parser',from_encoding='utf-8')
title = soup.find('dd',class_='lemmaWgt-lemmaTitle-title')
        if title !=None:
            title = title.find('h1')
        if title != None:
            data['title'] = title.get_text()
        else:
            data['title'] = ''
BeautifulSoap通过指定标签名字,标签属性内容来从一个html文档中定位一个符合要求的标签,并获取其属性及内容。BeautifulSoap的详细使用大家可以百度之~~~这里就不详细说了~~~

在这里,我们的任务是:从一个html页面中获取新的百度百科链接,获取该页面中的标题内容及摘要。下面给出网页解析器的代码:

# 解析网页数据
class HtmlParser(object):

	def parse(self,url,content):
		if url is None or content is None:
			return None

		soup = BeautifulSoup(content,'html.parser',from_encoding='utf-8')
		new_urls=self.__get_new_urls(url,soup)
		new_data=self.__get_new_data(url,soup)
		return new_urls,new_data

	def __get_new_urls(self,url,soup):
		new_urls=set()
		links = soup.find_all('a',href=re.compile('/view/\\d+.htm'))
		for link in links:
			new_url=urlparse.urljoin(url,link['href'])
			new_urls.add(new_url)

		return new_urls

	def __get_new_data(self,url,soup):
		data={}
		data['url']=url
		# <dd class="lemmaWgt-lemmaTitle-title"> <h1>Python</h1>
		title = soup.find('dd',class_='lemmaWgt-lemmaTitle-title')
		if title !=None:
			title = title.find('h1')
		if title != None:
			data['title'] = title.get_text()
		else:
			data['title'] = ''

		# <div class="lemma-summary" label-module="lemmaSummary">
		summary = soup.find('div', class_='lemma-summary')
		if summary != None:
			data['summary'] = summary.get_text()
		else:
			data['summary'] = ''

		return data

4) 爬取内容的输出器

这个也比较简单,主要是存储爬取到的数据,然后写到一个文件里面。

# 收集爬取到的数据以及将数据输出到文件中
class HtmlOutputer(object):

	def __init__(self):
		self.datas = []

	def collect(self,data):
		self.datas.append(data)

	def output(self):
		with open('output.html','wb') as f:
			f.write('<html>')
			f.write('<head><meta charset="UTF-8"></head>')
			f.write('<body>')
			f.write('<table>')
			try:
				for data in self.datas:
					f.write('<tr>')
					f.write('<td>%s</td>' % data['url'].encode('utf-8'))
					f.write('<td>%s</td>' % data['title'].encode('utf-8'))
					f.write('<td>%s</td>' % data['summary'].encode('utf-8'))
					f.write('</tr>')

					
			except Exception as e:
				print e
			finally:
				f.write('</table>')
				f.write('</body>')
				f.write('</html>')
				f.close()
上述代码提供了一个collect方法用来存储爬虫爬取到的数据,然后还提供了一个output方法将保存到内存中的数据输出到一个html文件中,并且以一个表格的形式呈现出来。

2. 爬虫运行效果

嗯...上述就是一个简单的爬虫的简单解析。谢谢~




以上是关于python轻量级爬虫的编写的主要内容,如果未能解决你的问题,请参考以下文章

Python学习使用Feapder框架,编写爬虫,爬取中国工程院院士信息

Scrapy:Python的爬虫框架

500 行 Python 代码构建一个轻量级爬虫框架

干货|500行Python代码构建一个轻量级爬虫框架(大神)

python爬虫框架 — Scrappy

Python 开发简单爬虫 - 基础框架