Python3 开发轻量级爬虫教程!
爬虫又被称为网页蜘蛛,网络机器人。是一种按照一定的规则,自动地抓取互联网上信息的程序或者脚本。 一、爬虫算法 在写爬虫时候有两种常用的算法可使用,即深度优先算法、广度优先算法。 深度优先算法 进群:548377875 ? 即可获取数十套PDF哦! 对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。直到访问完成后再返回到最上层,然后重复上述步骤。 广度优先算法 从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。 负载均衡 当爬取量很大的话,需要负载到多台服务器同时运行(搜索引擎都是这么做的)。但这样会出现一个问题,当 A 服务器已经爬取完成的 URL,但 B 服务器并不知道 A 是否爬取完成,这样会造成资源的浪费,那怎么办呢?如何突破爬虫的瓶颈? 其中最简单的便是 URL 分类。举个栗子:现在有 A、B、C、D、X 五台服务器同时运行爬虫,X 为负载均衡服务器。所有的 URL 都要经过 X 服务器进行分配, X 服务器遇到域名是 .com 结尾的就分配给 A,遇到 .cn 结尾就分配给 B,遇到 .net 结尾就分配给 C,其他域名都分配给 D。这样就解决了爬虫瓶颈的问题,这个问题可是谷歌的面试题。 二、爬虫逻辑 爬虫可大致分为五个部分:
爬虫逻辑可分解为如下几个部分:
三、开发轻量级爬虫 1. 调度器 spider.py #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # 【调度器】 # # 调度器又称为引擎,是爬虫逻辑实现的模块。 # # 爬虫逻辑可分解为如下几个部分: # # 1. 查询管理器中是否有待爬取的 URL # 2. 调度器从管理器中获取一个待爬取 URL # 3. 将获取到的 URL 交给下载器处理 # 4. 将下载器获取到的网页数据交给解析器处理 # 5. 将解析器处理后的 URL 集合交给管理器 # 6. 将解析器处理后的数据交给输出器 # 7. 重复上述步骤 # import manager,download,parser,output class Spider(object): def __init__(self): # 实例化 管理器、下载器、解析器、输出器 self.manager = manager.Manager() self.download = download.Download() self.parser = parser.Parser() self.output = output.Output() def spider(self,url): # 爬虫计数器 count = 0 # 将第一个 URL 放入管理器中 self.manager.add_url(url) # 判断管理器中 URL 的数量是否为 0 while self.manager.num_url(): try: # 从管理器中获取一个 URL new_url = self.manager.get_url() # 将获取到的 URL 交给下载器处理 html_cont = self.download.download(new_url) # 将 URL 和 下载器处理后的网页数据交给解析器处理 new_manager,new_data = self.parser.parser(new_url,html_cont) # 将解析器处理后的数据和新的 URL 分别交给管理器和输出器 self.manager.add_urls(new_manager) self.output.add_data(new_data) # 最多爬取 100 次 if count == 100: break count += 1 print('爬虫运行状态 ==> %d : %s' % (count,new_url)) except: print('爬虫爬取失败') # 当爬虫爬取完所有数据后,输出器将数据输出到文件 self.output.output() if __name__ == '__main__': # URL 入口(爬虫爬取的第一个 URL) url = 'http://www.cnblogs.com/peida/archive/2012/12/05/2803591.html' # 实例化调度器并启动爬虫 run = Spider() run.spider(url) 2. 管理器 manager.py #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # 【管理器】 # # 对外提供四个方法: # # 1. add_url(url) # 添加一个 URL,接收一个参数 URL # # 2. add_urls(url) # 批量添加 URL,接收一个参数 URL # # 3. num_url() # 管理器中URL 的数量 # # 4. get_url() # 从管理器中获取一个 URL # class Manager(object): def __init__(self): # 待爬取的 URL 集合 self.new_urls = set() # 已爬取的 URL 集合 self.old_urls = set() # 添加一个 URL def add_url(self,url): # 判断 url 是否为空,为空则返回 None if url is None: return # 判断 url 是否存在于【待爬取的 URL 集合】和【已爬取的 URL 集合】,如若都不在将新 url 添加到【待爬取的 URL 集合】中 if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) # 批量添加 URL def add_urls(self,urls): if urls is None or len(urls) == 0: return for url in urls: # 将 URL 集合交给 add_url() 函数处理 self.add_url(url) # 返回管理器中 URL 的数量 def num_url(self): return len(self.new_urls) != 0 # 从管理器中获取一个 URL def get_url(self): url = self.new_urls.pop() self.old_urls.add(url) return url 3. 下载器 download.py #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # 【下载器】 # # requests 模块需要安装 # sudo pip3 install requests # # 对外提供一个方法: # # download(url) # 下载网页中的内容,接收一个参数 URL # import requests class Download(object): def download(self,url): # 判断 URL 是否为空,为空直接返回 None if url is None: return None # 请求 URL response = requests.get(url = url) # 判断 URL 地址是否访问成功,若失败直接返回 None if response.status_code != 200: return None return response.text 4. 解析器 parser.py #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # 【解析器】 # # bs4 模块需要安装 # sudo pip3 install bs4 # # 对外提供一个方法: # # 1. parser(url) # BeautifulSoup DOM 树处理,接收两个参数 URL 和 html 内容 # # 对内提供两个方法: # # 1. _get_urls(url,soup) # 获取网页中的 URL,接收两个参数 URL 和 DOM 树 # # 2. _get_data(url,soup) # 获取网页中的数据,接收两个参数 URL 和 DOM 树 # import re from bs4 import BeautifulSoup class Parser(object): def _get_urls(self,url,soup): urls = set() links = soup.find_all('a',href=re.compile(r'/peida/archive/*')) for link in links: new_url = link['href'] urls.add(new_url) return urls def _get_data(self,soup): res_data = {} res_data['url'] = url title_node = soup.find('div',class_='post').find('a') res_data['title'] = title_node.get_text() return res_data def parser(self,html): # 判断 url 是否为空,或网页数据是否为空,为空则返回 None if url is None or html is None: return # 格式化 html 为 BeautifulSoup DOM 树 soup = BeautifulSoup(html,'html.parser') # 获取网页中的 URL urls = self._get_urls(url,soup) # 获取网页中的数据 data = self._get_data(url,soup) return urls,data 5. 输出器 output.py #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # 【输出器】 # # 对外提供两个方法: # # 1. add_data(data) # 存储网页数据,接收一个参数 data # # 2. output() # 将数据输出到 html 文件中 # class Output(object): def __init__(self): self.datas = [] def add_data(self,data): if data is None: return self.datas.append(data) def output(self): head = ''' 相关内容
|