问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
甲方爸爸需求-网站外链深度爬取小工具
安全工具
本菜也是第一次写这类小工具,以后也会一直写下去,提高自己!各位表哥一起加油吧!(说明一下文中的代码可以将qt5删掉变为脚本使用,如果想要工具的可以私聊我,这里没法传附件。。)
0X00 前言 前段日子,甲方爸爸需要对集团的各类门户网站做外链查询,看看有没有什么网站下面有那种见不得人的东西,相信各位老司机都懂得吧哈哈,于是开始在网上寻找一些爬虫软件(没办法,自己太菜了,只能找找大佬的软件) [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-48a58c76b42a91d2cf0b0267e93ff4b99655669e.jpg)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-48a58c76b42a91d2cf0b0267e93ff4b99655669e.jpg) 但是找了半天没找到合适的,甲方爸爸要求在这周内完成收集,那么多网站,要是手动搞实在是太累了,而且要找全啊,不能是单个页面下的,还要递归查找,最后实在找不到只能自己写了,拿出我尘封已久的pycharm就开始搞了。 0X01 思路探究 在我们开始写一个工具前,必须要有一套完整的思路(本萌新自己的思路各位大佬亲喷),我这里用我自己本次的思路进行一个总结如下: [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-5892a1383b45d7c07cd75544b09858be92e185bf.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-5892a1383b45d7c07cd75544b09858be92e185bf.png) 0X02 程序功能实现过程中问题总结 1.在爬虫连接时遇到反爬虫机制。 这个问题我在网上找了一些资料,基本都是通过headers字段进行反爬,由于这边甲方爸爸采用的白名单机制,且有相关的防爬waf,所以还是和甲方爸爸相关的运维配合解决了反爬问题,主要是时间确实不多,后续会进行这块的代码优化。 2.连接时候出现异常,各类变量为空。 这个就是当访问到某些特定URL时会出现无法连接的情况,然后返回的内容为none,就会出现一连串错误,这个时候简单做下异常处理,或者采用简单的if判断进行解决。 3.正则匹配不准确。 正则还是得多学学,搞了很久才弄出正确的正则。。。 [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-fb9ca3949ef17e92ba2e0c1edc686f98cf744ebe.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-fb9ca3949ef17e92ba2e0c1edc686f98cf744ebe.png) 4.使用递归深度爬取后发现程序容易出错且每次爬取结果不统一。 最开始选择用递归发现程序很容易出错,最后想了下用队列的方式就解决了这类问题,感觉还是队列好用啊。 5.存放外联和网站整体URL时list变量不好传递。 这个list变量由于一直在往里添加元素,最开始使用参数传递,发现不对劲,最后把他弄出全局变量就解决这个问题了,哈哈哈。 0x03 甩出主要代码 ```php import sys from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow ,QMessageBox from ui import Ui_Spider import requests from lxml import etree #from multiprocessing import Pool #from multiprocessing import Manager import time import re 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): # 全局url变量 global temp_list2 temp_list2 = [] # 全局外联变量 global temp_list temp_list = [] global quen_list quen_list = [] global count count = 0 def out_url(self): widgetres = self.write_text() with open('url.txt','w+',encoding='utf-8') as f: for i in widgetres: f.writelines(i + '\n') QMessageBox.about(self, '','导出成功') def out_wl_url(self): widgetres = temp_list with open('wl_url.txt','w+',encoding='utf-8') as f: for i in widgetres: f.writelines(i + '\n') QMessageBox.about(self, '','导出成功') def add_list(self): num = self.url_text.text() # 爬取标签列表 p_list = ['//@href', '//@src', '//@link'] # 判断是否为本域名参数 domain_url = self.doamin_text.text() domain_list = domain_url.split(";") #开始之前情况清空所有列表数据 self.url_list.clear() self.wl_list.clear() temp_list.clear() temp_list2.clear() quen_list.clear() # 判断是否为空 if len(num) == 0: QMessageBox.about(self,'','请输入url') if len(domain_url) == 0: QMessageBox.about(self, '', '请输入domain!') if len(num) !=0 and len(domain_list) != 0: self.pool_pc(p_list,num,domain_list) def sprider(self,reg, url, domain_url): if url not in temp_list2: # 将每次跑的url写进3.txt temp_list2.append(url) # 添加跑的url元素 self.url_list.addItem(str(url)) QApplication.processEvents() x = self.link_url(url) if x != None: # 获取页面源码 html = etree.HTML(x.content) tpl_content = self.get_tpt_content(reg, html) filter_list = self.get_filter_list(url, tpl_content) self.cycle(url, filter_list, domain_url) else: # q.put(url) time.sleep(0.01) def cycle(self, filter_list, domain_url): # 进行判断下方是否还有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 if d_url not in fl: 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) # q.put(url) time.sleep(0.01) def get_filter_list(self,url, tpl_content): # 过滤第一次讲有的//href前加上http://,filter_list1保存过滤后的列表元素 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] # 判断是否已'/'开头,是就添加前缀 if len(tpl_content) != 0: for tpl_c in tpl_content: if tpl_c[0:4] != 'http': if tpl_c[0:1] == '/': tpl = url_qinzui + tpl_c filter_list1.append(tpl) elif tpl_c[0:1] == '.': tpl = url_qinzui + '/' + tpl_c filter_list1.append(tpl) elif tpl_c[0:3] == 'www': tpl = tpl_c filter_list1.append(tpl) else: tpl = url_qinzui + '/' + tpl_c filter_list1.append(tpl) else: filter_list1.append(tpl_c) return filter_list1 def get_tpt_content(self,reg, html): all_content = [] for r in reg: 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) 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' } # 做异常处理,如果连接不同提示URL以及跳过 try: x = requests.get(url, allow_redirects=False, headers=head, timeout=2) if x != None: return x except: print('无法连接' + url) def write_text(self): # 存url url_list = [] # 存css css_list = [] # 存js js_list = [] # 存图片 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) # 组合列表 new_list = ['URL列表为:'] + url_list + ['\n\nJS列表为:'] + js_list + ['\n\nCSS列表为'] + \ css_list + ['\n\n图片列表为'] + img_list return new_list def pool_pc(self,p_list, seedUrl, domain_url): # 使用进程池 # pool = Pool() # q = Manager().Queue() # 当前页的处理 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,'','爬虫完毕') # pool.close() # pool.join() if __name__ == '__main__': app = QApplication(sys.argv) w = mwindow() w.show() sys.exit(app.exec_()) ``` 0x04 代码简单讲解 1.使用库以及框架 我使用的是UI库是Pyqt5,爬虫选的request,以及lmxl,正则就是re啦,还是很简单的。 2.主要函数功能简述 [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-4d085972c372bc9b4128f3655b38efa5f2beaccb.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-4d085972c372bc9b4128f3655b38efa5f2beaccb.png) 0x05 软件使用测试 1.将项目进行打包 pyinstaller -F --icon=favicon.icon spider\_wl.py --noconsole 2.运行spider\_wl.exe [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-cf9cc7ba6823127f4285b45a9366de123286c777.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-cf9cc7ba6823127f4285b45a9366de123286c777.png) url处输入要爬取的网址,domain处输入标识为本网站的字符,如wwww.baidu.com,domain输入baidu的话,就会将页面下的所有不包含baidu字符的url设置为外联,当然可以写多个标识,以;分隔就行。 [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-1781d84c6fd5082ba3e52a44163b287a7084fdc8.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-1781d84c6fd5082ba3e52a44163b287a7084fdc8.png) [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-b4a18e75e9f6f2d8d2e7b9b0921d931cd6a170ce.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-b4a18e75e9f6f2d8d2e7b9b0921d931cd6a170ce.png) [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-3702e6937fa38675b4f04a991961b1fbbbed9464.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-3702e6937fa38675b4f04a991961b1fbbbed9464.png) [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-c8748a20871a939a3a6b8d71e41a7cf19066b06c.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-c8748a20871a939a3a6b8d71e41a7cf19066b06c.png) [![](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-0c492ac127cf1633832f5460de7ced072ff4b4f0.png)](https://shs3.b.qianxin.com/attack_forum/2021/08/attach-0c492ac127cf1633832f5460de7ced072ff4b4f0.png)
发表于 2021-08-20 10:50:02
阅读 ( 5682 )
分类:
安全开发
2 推荐
收藏
0 条评论
请先
登录
后评论
soufaker
8 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!