标签:
嗯...今天来分享一下如何使用python编写一个简单的网络爬虫。说到爬虫,这简直就是广大懒惰的程序员和宅男们的福音啊,一次编写,想要啥资源就能爬啥资源,高至各种学习资源,论文资料,低至各种图片小视频(...)等等...嗯...这里讲解了如何搭建一个简单爬虫的框架之后,会基于该框架编写一个栗子,该栗子代码会从python的百科页面开始,爬取各种百科页面信息并记录下来。
注意,这里的标题是《*轻量级爬虫*》,之所以说是轻量级,是因为这里只涉及到静态网页的解析,至于AJAX异步加载,JS脚本什么的并不涉及。
先来代码链接~~~
噢,对了,这个爬虫有两个版本,一个是MySQL版,一个是内存板。有啥区别呢,就是前者是使用MySQL数据库存储已经访问过的URL的,后者则使用内存。前者的好处是,多次运行相互独立,不会重复爬取相同的URL,而后者不一样,每一次运行都会从相同的URL出发,重复爬取相同的URL,那是因为前者是持久化存储,而后者不是。一旦后者的程序关掉,所有已经被访问过的URL记录就会清空。但是,前者也有一个缺点,那就是运行速度比较慢...具体怎么样,大家把代码下载下来跑一下就清楚了。下面讲述的是内存存储版的~~~
在编写代码之前,我们应该先确定一个良好的代码框架,这也是一个优秀的程序员应有的习惯(咳咳...我还不算一个优秀的程序员...以后会是的...)。这里,我将会讲述一个简单爬虫的框架。
一个最基本的爬虫应该由一下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()
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集合中将其屏蔽。
这个很简单,我们使用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来处理异常即可,防止程序崩溃。
我们使用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
这个也比较简单,主要是存储爬取到的数据,然后写到一个文件里面。
# 收集爬取到的数据以及将数据输出到文件中 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文件中,并且以一个表格的形式呈现出来。
嗯...上述就是一个简单的爬虫的简单解析。谢谢~
标签:
原文地址:http://blog.csdn.net/ivan_zgj/article/details/50992611