您的位置:首页 > 编程语言 > Python开发

python轻量级爬虫的编写

2016-03-27 18:00 651 查看
嗯...今天来分享一下如何使用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. 爬虫运行效果





嗯...上述就是一个简单的爬虫的简单解析。谢谢~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: