【源码】python网络ARP抓包工具

本文介绍了如何使用Python的MVC架构(模型-视图-控制器)结合Scapy和Tkinter开发一个数据包嗅探器。应用通过Scapy捕获网络数据包,使用Tkinter构建用户界面,实现多线程以保证GUI响应性。
摘要由CSDN通过智能技术生成

系统架构与设计

MVC架构

应用程序采用了模型-视图-控制器(MVC)架构,这是一种用于应用程序开发的常用设计模式,可以将应用程序的输入、处理和输出分离。这样做既可以提高代码的可维护性,也便于将来的扩展。

  • 模型(Model): 在本应用中,模型层直接与Scapy交互,负责数据包的捕获和分析逻辑。
  • 视图(View): 视图层由Tkinter构建,为用户提供交互界面。
  • 控制器(Controller): 控制器连接模型和视图,处理用户输入并调用模型来反映数据变化。

关键类说明

  • PacketSnifferController:作为控制器,负责启动嗅探线程和更新视图层的数据。
  • WinGUI:构建并管理GUI组件,如按钮、表格、输入框等。
  • Win:继承自WinGUI,实现事件绑定和自定义样式。

技术实现细节

使用Tkinter构建GUI

Tkinter提供了一套丰富的控件来构建图形用户界面。在本项目中,我们利用了Tkinter的ButtonEntryComboboxScaleTreeview等控件来创建一个用户友好的界面。通过这些控件,用户可以轻松设置嗅探参数并启动嗅探过程。

多线程数据包嗅探

数据包嗅探是一个持续的过程,如果在主线程中执行,将阻塞GUI的响应。因此,我们采用threading模块创建一个新线程来进行数据包嗅探。这样,即使在捕获数据包时,用户界面也能保持响应性。

Scapy进行数据包捕获

Scapy是一个强大的交互式数据包处理程序,支持广泛的协议。在我们的应用程序中,Scapy用于捕获和分析ARP数据包。Scapy的sniff函数允许我们指定捕获的接口、数据包数量以及过滤规则,非常适合于构建灵活的网络嗅探器。

动态获取网络接口

通过psutil库,我们能够动态获取系统中的网络接口信息,并在GUI中以下拉列表的形式展示给用户。这增加了应用程序的灵活性,允许用户根据实际情况选择合适的网络接口进行嗅探。

应用程序使用

  1. 安装必要的库:pip install scapy psutil tkinter
  2. 运行脚本启动应用程序。
  3. 选择网络接口,设置要捕获的数据包数量。
  4. 点击“开始嗅探”按钮,观察捕获的数据包信息。

附上源码

import threading
import tkinter as tk
from tkinter.ttk import Treeview, Combobox, Button, Entry, Scale, Style
from scapy.all import sniff
from scapy.layers.l2 import Ether
from scapy.layers.l2 import ARP
import psutil
class PacketSnifferController:
    def __init__(self):
        self.win = None
        self.packet_count = 10  # 默认捕获数据包数量

    def init(self, win):
        self.win = win

    def start_sniffing(self):
        # 获取用户设置的数据包数量
        self.packet_count = self.win.tk_input_lrg2klel.get()

        # 启动数据包嗅探线程
        sniff_thread = threading.Thread(target=self.sniff_packets)
        sniff_thread.start()

    def sniff_packets(self):
        selected_interface = self.win.tk_select_box_lrg2i35c.get()
        print(self.packet_count,selected_interface)
        # 设置捕获条件,可以根据需要进行修改
        # 在这个例子中,只捕获前 self.packet_count 个 ARP 数据包
        packets = sniff(iface=selected_interface, count=int(self.packet_count), filter="arp", stop_filter=None)

        # 处理捕获到的数据包
        for packet in packets:
            self.packet_callback(packet)

    def packet_callback(self, packet):
        # 获取捕获的数据包信息
        captured_info = (
            packet[Ether].dst,
            packet[Ether].src,
            packet[Ether].type,
            packet[ARP].hwtype,
            packet[ARP].ptype,
            packet[ARP].hwlen,
            packet[ARP].plen,
            packet[ARP].op,
            packet[ARP].hwsrc,
            packet[ARP].psrc,
            packet[ARP].hwdst,
            packet[ARP].pdst
        )

        print("Captured info before insertion:", captured_info)  # 调试输出

        # 插入新行数据,从第一列开始
        self.win.tk_table_lrg2fz4k.insert("", tk.END, values=captured_info)

class WinGUI(tk.Tk):
    def __init__(self):
        super().__init__()
        self.__win()
        self.tk_button_lrg2fjic = self.__tk_button_lrg2fjic(self)
        self.tk_table_lrg2fz4k = self.__tk_table_lrg2fz4k(self)
        self.tk_label_lrg2h7am = self.__tk_label_lrg2h7am(self)
        self.tk_select_box_lrg2i35c = self.__tk_select_box_lrg2i35c(self)
        self.tk_frame_lrg2jofg = self.__tk_frame_lrg2jofg(self)
        self.tk_input_lrg2klel = self.__tk_input_lrg2klel(self.tk_frame_lrg2jofg)
        self.tk_scale_lrg2krvw = self.__tk_scale_lrg2krvw(self.tk_frame_lrg2jofg)
        self.tk_label_lrg2l0vn = self.__tk_label_lrg2l0vn(self.tk_frame_lrg2jofg)

    def __win(self):
        self.title("数据包嗅探器")
        # 设置窗口大小、居中
        width = 1600
        height = 500
        screenwidth = self.winfo_screenwidth()
        screenheight = self.winfo_screenheight()
        geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        self.geometry(geometry)

        self.resizable(width=False, height=False)

    def scrollbar_autohide(self, vbar, hbar, widget):
        """自动隐藏滚动条"""
        def show():
            if vbar: vbar.lift(widget)
            if hbar: hbar.lift(widget)
        def hide():
            if vbar: vbar.lower(widget)
            if hbar: hbar.lower(widget)
        hide()
        widget.bind("<Enter>", lambda e: show())
        if vbar: vbar.bind("<Enter>", lambda e: show())
        if vbar: vbar.bind("<Leave>", lambda e: hide())
        if hbar: hbar.bind("<Enter>", lambda e: show())
        if hbar: hbar.bind("<Leave>", lambda e: hide())
        widget.bind("<Leave>", lambda e: hide())

    def v_scrollbar(self, vbar, widget, x, y, w, h, pw, ph):
        widget.configure(yscrollcommand=vbar.set)
        vbar.config(command=widget.yview)
        vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')

    def h_scrollbar(self, hbar, widget, x, y, w, h, pw, ph):
        widget.configure(xscrollcommand=hbar.set)
        hbar.config(command=widget.xview)
        hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')

    def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):
        vbar, hbar = None, None
        if is_vbar:
            vbar = tk.Scrollbar(master)
            self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)
        if is_hbar:
            hbar = tk.Scrollbar(master, orient="horizontal")
            self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)
        self.scrollbar_autohide(vbar, hbar, widget)

    def __tk_button_lrg2fjic(self, parent):
        btn = Button(parent, text="开始嗅探", takefocus=False)
        btn.place(x=520, y=71, width=67, height=30)
        return btn

    def __tk_table_lrg2fz4k(self, parent):
        # 表头字段 表头宽度
        columns = {"目的地址": 119, "源地址": 179, "类型": 100, "硬件类型": 100, "协议类型": 100, "硬件地址长度": 130,
                   "协议地址长度": 130, "操作码": 100, "源硬件地址": 150, "源协议地址": 150, "目的硬件地址": 150,
                   "目的协议地址": 150}
        tk_table = Treeview(parent, show="headings", columns=list(columns))
        for text, width in columns.items():  # 批量设置列属性
            tk_table.heading(text, text=text, anchor='center')
            tk_table.column(text, anchor='center', width=width, stretch=False)  # stretch 不自动拉伸

        tk_table.place(x=0, y=166, width=1600, height=334)
        return tk_table

    def __tk_label_lrg2h7am(self, parent):
        label = tk.Label(parent, text="选择网络接口:", anchor="center")
        label.place(x=11, y=14, width=112, height=30)
        return label

    def __tk_select_box_lrg2i35c(self, parent):
        cb = Combobox(parent, state="readonly", values=list(psutil.net_if_stats().keys()))
        cb.place(x=138, y=16, width=150, height=30)
        return cb

    def __tk_frame_lrg2jofg(self, parent):
        frame = tk.Frame(parent)
        frame.place(x=312, y=2, width=200, height=150)
        return frame

    def __tk_input_lrg2klel(self, parent):
        ipt = Entry(parent)
        ipt.insert(0, "10")  # 设置默认值为 "10"
        ipt.place(x=153, y=100, width=41, height=30)
        return ipt

    def __tk_scale_lrg2krvw(self, parent):
        scale = Scale(parent, orient=tk.HORIZONTAL, from_=1, to=100, command=self.update_entry_value)
        scale.place(x=11, y=98, width=130, height=30)
        return scale

    def update_entry_value(self, value):
        try:
            int_value = int(float(value))
            self.tk_input_lrg2klel.delete(0, tk.END)
            self.tk_input_lrg2klel.insert(0, str(int_value))
        except ValueError:
            # 处理无效值的情况,可以在这里添加适当的错误处理或默认值
            pass

    def __tk_label_lrg2l0vn(self, parent):
        label = tk.Label(parent, text="捕获数据包数量", anchor="center")
        label.place(x=10, y=28, width=180, height=30)
        return label

class Win(WinGUI):
    def __init__(self, controller):
        self.ctl = controller
        super().__init__()
        self.__event_bind()
        self.__style_config()
        self.ctl.init(self)

    def __event_bind(self):
        self.tk_button_lrg2fjic.config(command=self.ctl.start_sniffing)

    def __style_config(self):
        # 设置 Treeview 样式
        style = Style()
        style.configure("Treeview", rowheight=30)
        style.configure("Treeview.Heading", font=("Arial", 10, "bold"))

if __name__ == "__main__":
    controller = PacketSnifferController()
    win = Win(controller)
    win.mainloop()

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 安居客数据抓取源码Python实现的方法: Step 1:导入所需模块 在Python中使用requests和BeautifulSoup库来爬取网页的内容和进行数据解析。 import requests from bs4 import BeautifulSoup Step 2:设置请求头 在爬虫中,设置请求头是非常重要的一个步骤,因为一些网站会针对某类浏览器或爬虫进行限制,并对其进行处理。 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0;Win64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} Step 3:爬取页面 首先,我们需要先找到想要抓取的页面网址,并通过requests库发送请求,得到响应内容。在该网址中,通过page参数来获取页面的页数。 def get_page_content(url): page_content = [] for page in range(1, 51): print('正在爬取第%s页...' % page) r = requests.get(url + '&page=%d' % page, headers=headers) soup = BeautifulSoup(r.content, 'html.parser') page_content.append(soup) return page_content Step 4:数据解析 使用BeautifulSoup解析网页内容并获取数据。 def get_house_info(content): house_info = [] for page in content: house_list = page.select('div#listCon dl') for house in house_list: info_dict = {} info_dict['title'] = house.select('p.tit a')[0].text.strip() info_dict['price'] = house.select('span.price')[0].text.strip() info_dict['desc'] = house.select('p.desc a')[0].text.strip() info_dict['address'] = house.select('p.add')[0].text.strip() house_info.append(info_dict) return house_info Step 5:存储数据 将获取到的数据保存到CSV文件中。 def save_to_csv(data): import csv with open('house_info.csv', 'w', newline='', encoding='utf-8') as f: fieldnames = ['title', 'price', 'desc', 'address'] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() for row in data: writer.writerow(row) 最后,将上述函数整合起来并执行。 if __name__ == "__main__": url = 'https://tj.anjuke.com/sale/p2/#filtersort' page_content = get_page_content(url) house_info = get_house_info(page_content) save_to_csv(house_info) print('数据已保存到CSV文件中...') ### 回答2: 抓取安居客数据源码使用Python语言编写,可以通过网络爬虫技术实现。该程序的主要功能是通过网页分析和数据解析技术,抓取安居客网站上的房屋出租信息,并将其保存在本地数据仓库中。以下是大致的实现步骤: 1. 准备工作:安装Python编程环境,并安装相关开发库,如requests、BeautifulSoup等。 2. 确定目标网站:选择安居客网站作为抓取目标,并确定需要抓取的页面分类和关键词等搜索条件。 3. 网络请求:使用Python的requests库向目标网站发送HTTP请求,并模拟浏览器行为,如添加User-Agent 的请求头部等,以获取服务器返回的网页内容。 4. 数据解析:使用BeautifulSoup库对网页进行分析和解析,提取目标数据,并将其提取为结构化的数据格式,如json等。 5. 数据存储:将提取的数据存储在本地数据仓库中,如SQLite、MongoDB等,以方便后续数据处理和分析。 6. 定期更新:使用Python的定时任务程序,如crontab 或者 celery等,对目标网站进行定期更新,并自动抓取新增数据。 总之,通过Python语言编写的网络爬虫程序可以快捷、高效地实现抓取网站数据的目的,这不仅为各类数据分析和处理提供了便利,同时也需要遵守相关的法律法规,确保数据采集和用途的合法性。 ### 回答3: 抓取安居客数据的源码使用Python语言编写。通过网络爬虫技术,程序可以从安居客网站上获取房源数据信息,包括位置、面积、价格等相关信息。以下是抓取安居客数据的源码: ```python import requests from lxml import etree url = 'https://www.anjuke.com/fangjia/guangzhou2020/' response = requests.get(url) html = etree.HTML(response.content.decode()) data = [] for item in html.xpath('//div[@data-from="xfjs-new"]'): info = {} info['name'] = item.xpath('.//h3/a/text()')[0].strip() info['address'] = item.xpath('.//address/text()')[0].strip() info['price'] = item.xpath('.//strong/text()')[0].strip() data.append(info) print(data) ``` 该源码使用requests库获取网页内容,并使用lxml库解析网页内容。通过Xpath语法,程序可以定位到需要获取的房源信息,将其存储到字典中,最后将所有字典存储到列表中,并输出该列表。这样就可以获取到安居客网站上的房源信息了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农之家★资源共享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值