美文网首页Python新世界
Python3 开发轻量级爬虫教程!

Python3 开发轻量级爬虫教程!

作者: 919b0c54458f | 来源:发表于2018-09-30 13:30 被阅读8次

爬虫又被称为网页蜘蛛,网络机器人。是一种按照一定的规则,自动地抓取互联网上信息的程序或者脚本。

一、爬虫算法

在写爬虫时候有两种常用的算法可使用,即深度优先算法、广度优先算法。

深度优先算法

进群:548377875   即可获取数十套PDF哦!

对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。直到访问完成后再返回到最上层,然后重复上述步骤。

广度优先算法

从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。

负载均衡

当爬取量很大的话,需要负载到多台服务器同时运行(搜索引擎都是这么做的)。但这样会出现一个问题,当 A 服务器已经爬取完成的 URL,但 B 服务器并不知道 A 是否爬取完成,这样会造成资源的浪费,那怎么办呢?如何突破爬虫的瓶颈?

其中最简单的便是 URL 分类。举个栗子:现在有 A、B、C、D、X 五台服务器同时运行爬虫,X 为负载均衡服务器。所有的 URL 都要经过 X 服务器进行分配, X 服务器遇到域名是 .com 结尾的就分配给 A,遇到 .cn 结尾就分配给 B,遇到 .net 结尾就分配给 C,其他域名都分配给 D。这样就解决了爬虫瓶颈的问题,这个问题可是谷歌的面试题。

二、爬虫逻辑

爬虫可大致分为五个部分:

调度器:引擎,是爬虫逻辑实现的模块

管理器:URL 管理器,负责新增、删除、获取、存储、计数等功能,避免爬取重复的 URL。

下载器:HTML 下载器,将 URL 地址中的 HTML 内容获取到

解析器:HTML 解析器,将 HTML 获取到的内容进行分析

输出器:将分析完成后的数据进行输出、存储、利用等

爬虫逻辑可分解为如下几个部分:

查询管理器中是否有待爬取的 URL

调度器从管理器中获取一个待爬取 URL

将获取到的 URL 交给下载器处理

将下载器获取到的网页数据交给解析器处理

将解析器处理后的 URL 集合交给管理器

将解析器处理后的数据交给输出器

重复上述步骤

三、开发轻量级爬虫

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, url, 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, url, 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 = '''

'''

foot = '''

'''

with open('CSDN.html', 'w') as f:

f.write(head)

for data in self.datas:

f.write('%s' % (data['url'], data['url']))

f.write('%s' % data['title'])

f.write(foot)

运行结果:

今天就聊到这里啦,大家记得点赞收藏,分享转发,关注哟!

相关文章

网友评论

    本文标题:Python3 开发轻量级爬虫教程!

    本文链接:https://www.haomeiwen.com/subject/splwoftx.html