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