甲方爸爸需求-网站外链深度爬取小工具
字数 1145 2025-08-09 18:44:12
网站外链深度爬取工具开发指南
0X00 项目背景
甲方安全需求:需要对集团各类门户网站进行外链查询,检查是否存在违规或恶意链接。
技术挑战:
- 需要递归查找所有页面下的外链
- 短时间内完成大量网站的收集工作
- 需要区分站内链接和站外链接
0X01 技术方案设计
整体思路
- 爬取策略:采用广度优先搜索(BFS)方式遍历网站
- 链接识别:通过HTML标签属性(href/src/link)提取链接
- 链接分类:根据域名标识区分站内链接和站外链接
- 结果输出:分类保存URL到不同文件
技术选型
- GUI框架:PyQt5
- 爬虫库:requests + lxml
- 正则处理:re
- 打包工具:PyInstaller
0X02 核心功能实现
1. 主程序结构
class mwindow(QWidget, Ui_Spider):
def __init__(self):
super(mwindow, self).__init__()
self.setupUi(self)
self.initUi()
self.initarg()
def initUi(self):
# 绑定按钮事件
self.spider_button.clicked.connect(self.add_list)
self.url_button.clicked.connect(self.out_url)
self.wl_button.clicked.connect(self.out_wl_url)
def initarg(self):
# 全局变量初始化
global temp_list2, temp_list, quen_list, count
temp_list2 = [] # 存储所有URL
temp_list = [] # 存储外链URL
quen_list = [] # 待爬队列
count = 0 # 计数器
2. 爬虫核心逻辑
def sprider(self, reg, url, domain_url):
if url not in temp_list2:
temp_list2.append(url) # 记录已访问URL
self.url_list.addItem(str(url)) # UI显示
QApplication.processEvents()
x = self.link_url(url) # 获取页面内容
if x != None:
html = etree.HTML(x.content) # 解析HTML
tpl_content = self.get_tpt_content(reg, html) # 提取链接
filter_list = self.get_filter_list(url, tpl_content) # 处理链接
self.cycle(filter_list, domain_url) # 分类处理
3. 链接提取与处理
def get_tpt_content(self, reg, html):
all_content = []
for r in reg: # 遍历所有标签属性(href/src/link)
try:
tpl_content = list(set(html.xpath(r))) # 去重
except:
continue
# 清理数据
tpl_content = [tp for tp in tpl_content if tp != '']
tpl_content = [' '.join([i.strip() for i in tp.strip().split('\t')])
for tp in tpl_content]
all_content += tpl_content
return set(all_content)
4. 链接分类逻辑
def cycle(self, filter_list, domain_url):
flag = 0
temp_filter_list = []
set(filter_list)
for fl in filter_list:
for d_url in domain_url:
if d_url in fl: # 站内链接
if fl not in temp_list2:
temp_filter_list.append(fl)
flag = 1
else: # 外链
temp_list.append(fl)
self.wl_list.addItem(str(fl))
QApplication.processEvents()
if flag == 1: # 将站内链接加入队列继续爬取
for te in set(temp_filter_list):
quen_list.append(te)
time.sleep(0.01) # 礼貌爬取
5. URL规范化处理
def get_filter_list(self, url, tpl_content):
filter_list1 = []
# 提取URL前缀(协议+域名)
paren = r"(?:https|http)?w.]da-zA-Z]))+(?:[com|cn|org|js|css|img|net]+)"
url_qinzui = re.findall(paren, url)[0]
for tpl_c in tpl_content:
if tpl_c[0:4] != 'http':
if tpl_c[0:1] == '/':
tpl = url_qinzui + tpl_c
elif tpl_c[0:1] != '/':
tpl = url_qinzui + '/' + tpl_c
elif tpl_c[0:3] == 'www':
tpl = tpl_c
else:
tpl = url_qinzui + '/' + tpl_c
filter_list1.append(tpl)
else:
filter_list1.append(tpl_c)
return filter_list1
0X03 关键技术点
1. 反爬虫处理方案
- 使用标准浏览器User-Agent头
- 设置合理的请求间隔(time.sleep)
- 配合甲方运维设置白名单
- 请求时设置超时(timeout=2)
def link_url(self, url):
head = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0'
}
try:
x = requests.get(url, allow_redirects=False, headers=head, timeout=2)
if x != None:
return x
except:
print('无法连接' + url)
2. 广度优先搜索实现
使用队列(quen_list)替代递归,避免递归深度问题:
def pool_pc(self, p_list, seedUrl, domain_url):
# 初始URL处理
self.sprider(p_list, seedUrl, domain_url)
# 队列处理
while quen_list:
url = quen_list.pop(0) # 从队列头部取出
self.sprider(p_list, url, domain_url)
QMessageBox.about(self, '', '爬虫完毕')
3. 结果分类输出
将结果按类型分类保存:
def write_text(self):
url_list = [] # 普通URL
css_list = [] # CSS文件
js_list = [] # JS文件
img_list = [] # 图片文件
all_list = list(set(temp_list2))
for a in all_list:
h_3 = (a[-3:]).lower()
h_4 = (a[-4:]).lower()
if h_3 == '.js':
js_list.append(a)
elif h_4 == '.css':
css_list.append(a)
elif h_4 == '.jpg' or h_4 == '.png' or h_4 == '.gif':
img_list.append(a)
else:
url_list.append(a)
return ['URL列表为:'] + url_list + ['\n\nJS列表为:'] + js_list +
['\n\nCSS列表为'] + css_list + ['\n\n图片列表为'] + img_list
0X04 使用说明
1. 软件打包
pyinstaller -F --icon=favicon.icon spider_wl.py --noconsole
2. 运行参数
- URL输入框:输入要爬取的起始URL(如https://www.example.com)
- Domain输入框:输入标识本站的字符串,多个用分号分隔(如example;test)
3. 功能按钮
- 开始爬取:启动爬虫程序
- 导出URL:将所有URL保存到url.txt
- 导出外链:将所有外链URL保存到wl_url.txt
0X05 开发经验总结
1. 遇到的问题及解决方案
| 问题 | 解决方案 |
|---|---|
| 反爬虫机制 | 使用标准请求头,配合运维设置白名单 |
| 连接异常 | 增加异常处理,跳过无效URL |
| 正则不准确 | 优化正则表达式,多次测试调整 |
| 递归问题 | 改用队列实现广度优先搜索 |
| 变量传递 | 使用全局变量替代参数传递 |
2. 最佳实践建议
-
爬虫礼仪:
- 设置合理的请求间隔
- 遵守robots.txt规则
- 控制并发数量
-
代码健壮性:
- 增加完善的异常处理
- 记录爬取日志
- 支持断点续爬
-
性能优化:
- 使用多线程/多进程
- 实现去重机制
- 优化正则表达式
-
扩展功能:
- 添加深度控制参数
- 支持代理设置
- 增加结果分析功能
0X06 完整代码结构
spider_wl.py
├── mwindow类
│ ├── __init__: 初始化UI和参数
│ ├── initUi: 绑定按钮事件
│ ├── initarg: 初始化全局变量
│ ├── add_list: 开始爬取入口
│ ├── sprider: 爬虫核心方法
│ ├── cycle: 链接分类处理
│ ├── get_filter_list: URL规范化
│ ├── get_tpt_content: 提取页面链接
│ ├── link_url: 请求页面内容
│ ├── write_text: 结果分类
│ ├── out_url: 导出URL
│ ├── out_wl_url: 导出外链
│ └── pool_pc: 队列调度
└── 主程序入口
通过本工具,可以高效完成网站外链的深度爬取和分析工作,满足甲方安全审计的需求。开发者可根据实际需求进一步扩展功能,如增加自动化分析、危险链接识别等高级特性。