一个简单的网站爬虫

  • 1 项目介绍
  • 1.1 项目由来
  • 1.2 项目功能
  • 1.3 项目不足
  • 2 项目代码
  • 2.1 框架代码
  • 2.2 项目代码
  • 3 总结


1 项目介绍

1.1 项目由来

因为作者接触最多的就是爬虫领域,但是平时编写爬虫都是针对网站编写相应的爬虫,每次都是从头开始写,代码复用率极低。之前有用过Scripy等爬虫框架,实在用不习惯,于是想着开发一套自己的爬虫框架,以简洁,实用为主。于是我便开始了SpiderLegion(爬虫军团)框架的编写,交流群号我会放置在评论区,欢迎大家参与到爬虫框架的研究。
爬虫框架GitHub开源地址https://github.com/ParzivalLee/SpiderLegion 本项目Github开源地址https://github.com/ParzivalLee/webspider 本项目主要是对SpiderLegion框架的一次实战,用来寻找SpiderLegion存在的问题并进行更好的优化

1.2 项目功能

本项目仅用作简单的网站公开静态内容的获取,也就是将网站所有可见的信息获取到本地,唯一的亮点就是采用的多线程,速度会比较快

1.3 项目不足

那就太多了,比如目前线程是写死的,限制了host,参数的调节不够灵活,容易出现错误等等。怎么说呢,目前这个项目只能算是一个Demo,而且毕竟这个项目的实用性和技术性并不是很强。

2 项目代码

完整的项目代码大家可以从GitHub下载,在这里展示一下比较核心的代码

2.1 框架代码

目前的还称不上的框架吧,只是导入了一个基础的库,也算是比较核心的库,主要用于多线程计算。
小蜘蛛类,爬虫军团最基础、最核心的类

class Spider:
    def __init__(self,
                 info={'restTime': 1},
                 tasks=[]):
        self.info = info	# 小蜘蛛信息,用于传递参数和信息记录等
        self.tasks = tasks  # 任务列表,小蜘蛛执行的任务信息会从这里获取
        self.count = 0      # 计数器,如果人物列表为空,小蜘蛛将在等待超时过后停止任务
        self.isActive = False

这一段代码展示的是爬虫如何执行

# 开始执行任务
    def start(self):
        self.isActive = True
        while self.isActive:
            if self.tasks:
                self.count = 0
                #爬虫会从任务列表获取任务信息,其中必须包含'function'和'params',及任务函数和任务参数
                task = self.tasks.pop(0)
                task['function'](task['params'])
            else:
                time.sleep(3)
                self.count += 1
                # 若一分钟内没有任务则结束
                if self.count >= 20:
                    self.isActive = False
                    break

    # 停止任务
    def stop(self):
        self.isActive = False

小蜘蛛类的设计比较简单,因为我比较喜欢简洁
总之其工作模式就是

  • 建立线程执行start
  • 每个线程,向任务列表获取任务信息
  • 如果任务列表存在任务,则根据任务信息执行任务
  • 如果任务列表为空,则等待,若等待过久,则停止任务
    本项目主要是依托该类实现多线程

2.2 项目代码

本项目主要通过正则表达式解析网址

# 编译正则表达式
url_matches = list()
url_matches.append(re.compile(r"href=\"{0,1}([^><\"\' ]*)\"{0,1}"))
url_matches.append(re.compile(r"src=\"{0,1}([^><\"\' ]*)\"{0,1}"))

一下为主要获取函数

def scrape(params):
    response = requests.get(params['url'])
    # 判断请求状态,如果不是200和301则跳过
    print("url:%s\tstatus code:%d" % (response.url, response.status_code))
    if response.status_code != 200 and response.status_code != 301:
        gotUrl.add(params['url'])
        return

    saveFile(params['url'], response.content)

    # 判断是否为文本内容,是则解析
    if response.encoding:
        urls = set()
        for r_url in url_matches:
            # 将解析的url添加到集合
            urls.update(r_url.findall(response.text))
        urls = urls.difference(gotUrl)

通过以下代码启动爬虫

# 这里将生成第一个任务
spider.tasks.append({'function': scrape, 'params': {'url': start_url}})
# 生成线程
for i in range(threadNumber):
    threading.Thread(target=spider.start).start()

在主要函数中会通过如下代码生成新的任务

params = dict()
            params['url'] = url
            spider.tasks.append({'function': scrape, 'params': params})

如此循环往复,直到全部网页内容被获取,。。。或者出现错误。。。

3 总结

这个就是目前项目的情况,实用性不高,技术性不强,问题可能比功能多得多,后面会不断完善的。也望各路大神能给出宝贵的意见,如果能参与到爬虫军团的建设中就更好了!