百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

苦等了四年的《釜山行2》,你就给我这

toyiye 2024-06-21 12:05 6 浏览 0 评论



7月15日,《釜山行》的续集《釜山行2:半岛》在首尔正式上映,不少朋友都对它充满期待。


四年前,第一部《釜山行》上映,丧尸沦陷中,釜山是希望。四年后,整个半岛全部沦陷,正式成为丧尸半岛。


据小伙伴观后感说,这部《釜山行2》,惊喜其实并不多。倒不至于有多烂,只不过,相比让人惊喜的第一部,作为续集的《釜山行2》,投资更大、场面更大,但是,影片本身带给观众的冲击却少了很多。


今天我们就用Python来回顾一下四年前的《釜山行》吧!


今天的项目将使用python编写代码实现对《釜山行》文本的人物关系提取,最终利用Gephi软件对提取的人物关系绘制人物关系图。

实体间的共现是一种基于统计的信息提取。关系紧密的人物往往会在文本中多段内同时出现,可以通过识别文本中已确定的实体(人名),计算不同实体共同出现的次数和比率。

当比率大于某一阈值,我们认为两个实体间存在某种联系。这种联系可以具体细化,但提取过程也更加复杂。因此在此课程只介绍最基础的共现网络。

1.开发环境

剧本

http://7xktmz.com1.z0.glb.clouddn.com/Train%20to%20Busan.txt

字典

http://labfile.oss.aliyuncs.com/courses/677/dict.txt

gephi
Python2+jieba库

2.实验过程


开始编写我们的代码。

import os, sys

import jieba, codecs, math

import jieba.posseg as pseg


names = {}

relationships = {}

lineNames = []


字典类型names保存人物,该字典的键为人物名称,值为该人物在全文中出现的次数。

字典类型relationships保存人物关系的有向边,该字典的键为有向边的起点,值为一个字典edge,edge的键是有向边的终点,值是有向边的权值,代表两个人物之间联系的紧密程度。

lineNames是一个缓存变量,保存对每一段分词得到当前段中出现的人物名称,lineNames[i]是一个列表,列表中存储第i段中出现过的人物。

jieba.load_userdict("dict.txt")

with codecs.open("to_train.txt", "r", "utf8") as f:

for line in f.readlines():

poss = pseg.cut(line)

lineNames.append([])

for w in poss:

if w.flag != "nr" or len(w.word) < 2:

continue

lineNames[-1].append(w.word)

if names.get(w.word) is None:

names[w.word] = 0

relationships[w.word] = {}

names[w.word] += 1


在具体实现过程中,读入剧本的每一行,对其做分词。

提取该行中出现的人物集存入lineNames中。之后对出现的人物,更新他们在names中的出现次数。

for line in lineNames:

for name1 in line:

for name2 in line:

if name1 == name2:

continue

if relationships[name1].get(name2) is None:

relationships[name1][name2]= 1

else:

relationships[name1][name2] = relationships[name1][name2]+ 1


对于lineNames中每一行,我们为该行中出现的所有人物两两相连。

如果两个人物之间尚未有边建立,则将新建的边权值设为1,否则将已存在的边的权值加1。

这种方法将产生很多的冗余边,这些冗余边将在最后处理。

with codecs.open("node.txt", "w", "gbk") as f:

f.write("Id Label Weight\r\n")

for name, times in names.items():

f.write(name + " " + name + " " + str(times) + "\r\n")


with codecs.open("edge.txt", "w", "gbk") as f:

f.write("Source Target Weight\r\n")

for name, edges in relationships.items():

for v, w in edges.items():

if w > 3:

f.write(name + " " + v + " " + str(w) + "\r\n")


将已经建好的names和relationships输出到文本,以方便gephi可视化处理。输出边的过程中可以过滤可能是冗余的边,这里假设共同出现次数少于3次的是冗余边,则在输出时跳过这样的边。


完整的代码如下:


运行得到节点集合node.txt,边集合edge.txt。


下面使用gephi这个软件来将人物关系可视化。

启动gephi,分别选择节点表格和边表格导入上面代码中生成的两个文件,分隔符选择空格,编码选择GB2312。



可以在最上方的数据资料选项卡中查看图中所有的边和节点,对于分词不准确导致的噪音可以手动删除。

分别点击右侧统计栏中平均度和模块化运行计算。模块化运算时Resolution值填写0.5。


点击左上角外观中节点第一个选项卡,选择数值设定,选择Modularity Class,点击应用。



点击左上角外观中节点第二个选项卡,选择数值设定,选择连入度,最小尺寸填10,最大尺寸填40,点击应用。



选择左下角布局中的Force Atlas,斥力强度填写20000.0,吸引强度填写 1.0。点击运行,稍后点击停止。



点染色根据模块化计算结果不定,但染色效果大致相同。

点击最上方的预览按钮,选中左侧节点标签中显示标签选项,并选择一种字体。


点击刷新按钮,右侧显示最终的人物关系图。为了优化显示的效果,还可以调整左边的参数。

以上就是釜山行人物关系的图谱,是不是很简单?


说起丧尸,我就想起僵尸。今天再教你一招,用Python揪出你微信里的僵尸粉!


你一定也遇到过,突然想联系一位很久没有联系的朋友,发现对方早就已经把你删除了,而你还一无所知(好尴尬呀)。


这就是所谓的僵尸粉,他们默默地躺在你微信联系人中,你傻傻的以为对方还是好朋友,而其实,对方早就把你从好友列表中删除了,现在我们来揪出他们吧!


1、准备工作

在开始编写脚本之前,需要做好以下准备工作:

一部 Root 后的 Android 手机或者模拟器,如果没有 Root 的设备,可以使用网易 MuMu 模拟器;

Android 的开发环境、Android Studio;

sqlcipher 图形化工具;

自动化工具:Python 虚拟环境下安装 pocoui。


整个操作分为 3 个步骤,分别是破解微信数据库,筛选出通信录中的好友、模拟给好友转账得到僵尸粉的数据、同时删除好友中所有的僵尸粉。


第 1 步,我们需要破解微信 App 的数据库。

首先,我们使用 Android Studio 新建一个项目,在项目初始化的时候,授予应用管理员权限,以及修改微信目录的读写权限功能。

接下来,我们来获取一下微信数据库的密码。


数据库的密码是由设备的 imei 和微信的 uid 通过 md5 算法生成得到的。


下面,我们就可以使用 SQLCipher 依赖库来对微信数据库进行查询,我们需要为项目添加以下依赖,方便我们操作数据库。

//我们需要对项目增加依赖
implementation 'net.zetetic:android-database-sqlcipher:3.5.4@aar'

通过上面得到的密码能够打开加密数据库,然后查询rcontact表获取微信通讯录内所有好友的微信号、微信名称以及用户名等一些数据。

这里需要注意,数据库中 rcontact 表的数据相对是比较杂乱的,除了正常的好友数据之外,微信的黑名单好友、已经删除的好友、关注的公众号、加入的微信群等一些其他的数据也包含在里面,需要我们通过 type 和 verifyFlag 字段进行筛选。

为了进行 Python 接下来的操作,我们要将查询到的好友数据写入到 csv 文件中来。

/***
 * 写入数据到csv中
 * @param output_path
 * @param contacts
 */
public static void writeCsvFile(String output_path, List<Contact> contacts)
{
    try
    {
        File file = new File(output_path);
        //删除之前保存的文件
        if (file.exists())
        {
             file.delete();
        }
        BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));
        // 添加头部名称
        bw.write("userName" + "," + "alias" + "," + "nickName");
        bw.newLine();
        for (int i = 0; i < contacts.size(); i++)
        {
            bw.write(contacts.get(i).getUserName() + "," + contacts.get(i).getAlias() + "," + contacts.get(i).getNickName());
            bw.newLine();
        }
        bw.close();
     } catch (IOException e)
     {
         e.printStackTrace();
     }
}

第 2 步,模拟给好友转账,从而判断这个好友是否是「僵尸粉」。

首先,我们需要初始化 Airtest,接下来利用 adb 把第 1 步生成的数据从手机里导出到本地中去。

def __init_airtest(self):
        """
        初始化Airtest
        :return:
        """
        device_1 = Android('822QEDTL225T7')
        # device_1 = Android('emulator-5554')

        connect_device("android:///")

        self.poco = AndroidUiautomationPoco(device_1, screenshot_each_action=False)

        auto_setup(__file__)

def export_wx_db_from_phone(target_path):
    """
    从手机中导出通信录数据
    :param target_path:
    :return:
    """
    # 微信通信录数据
    wx_db_source_path = "/data/data/com.xingag.crack_wx/wx_data.csv"

    # 导出到本地
    os.popen('adb pull %s %s' % (wx_db_source_path, target_path))

接下来就是一系列的自动化操作。


打开微信App,遍历所有的好友列表,获取到每一个好友的微信号去搜索对应的好友,然后跳转到与好友的聊天界面中。

def __to_friend_chat_page(self, weixin_id):
        """
        点击到一个好友的聊天界面
        :param weixin_id:
        :param weixin_name:
        :return:
        """
        # 1、点击搜索
        element_search = self.__wait_for_element_exists(self.id_search)
        element_search.click()

        print('点击搜索')

        # 2、搜索框
        element_search_input = self.__wait_for_element_exists(self.id_search_input)
        element_search_input.set_text(weixin_id)

        # 3、搜索列表
        element_search_result_list = self.__wait_for_element_exists(self.id_search_result_list)

        # 3.1 是否存在对应的联系人,如果存在就在第一个子View布局下
        # 注意:可能出现最常用的聊天列表,这里需要进行判断
        index_tips = 0
        for index, element_search_result in enumerate(element_search_result_list.children()):
            # 联系人的Tips
            # if element_search_result_list.children()[0].offspring(self.id_contact_tips).exists():

            if element_search_result.offspring(text=self.text_contact_tips).exists():
                index_tips = index
                break

        # 4、点击第一个联系人进入聊天界面
        element_search_result_list.children()[index_tips + 1].click()

下面我们尝试着给对方转账,如果好友关系是正常的,就会跳出一个支付页面让你输入密码。

def __judge_is_friend(self, weixin_id, weixin_name):
        """
        判断是不是微信好友
        :param weixin_id: 微信号
        :return:
        """
        # 尝试给好友转账,设置一个小额度,以防止刷脸直接支付了
        # 如果对方是你的好友,接下来会让你输入密码,关掉页面就行了
        # 如果对方不是你的好友,会提示不是你的好友,不能继续操作了
        # 5、点击好友界面的+按钮
        self.poco(self.id_chat_more_button).click()

        # 6、点击转账按钮
        self.poco(self.id_chat_more_container).offspring(text=self.text_chat_transfer_account_text).click()

        # 7、输入金额
        self.poco(self.id_transfer_account_input).set_text(self.money)

        # 8、点击转账按钮
        self.poco(self.id_transfer_account_container).offspring(text=self.text_chat_transfer_account_text).click()

如果是「僵尸粉」,就会弹出一个警告提示的对话框,提示你不是收款方的微信好友,没法完成转账的操作。如下图:

通过警告对话框是否存在,就可以判断出好友的关系是否正常。非正常的好友关系,包含:僵尸粉、对方账号异常等一些其他的情况。

# 10.弹出警告对话框# 弹出好友关系不正常
if element_transfer_account_result_button:
     # 提示内容
     ransfer_account_result_tips = self.poco(self.id_transfer_account_result_tips).get_text()

     if self.text_friend_no_tips in transfer_account_result_tips:
         print('注意!%s已经把你拉黑了!!!' % weixin_name)
         self.friend_black_list.append({
                    'id': weixin_id,
                    'nickName': weixin_name
                })
         write_to_file(self.path_black_list, 'id:%s,nickName:%s' % (weixin_id, weixin_name))
     elif self.text_friend_limit_tips in transfer_account_result_tips:
         print('%s账号收到限制!!!' % weixin_name)
         write_to_file(self.path_account_limit, 'id:%s,nickName:%s' % (weixin_id, weixin_name))
     elif self.text_friend_is_norm in transfer_account_result_tips:
         print('%s好友关系不正常!!!' % weixin_name)
         write_to_file(self.path_relationship_unnormal, 'id:%s,nickName:%s' % (weixin_id, weixin_name))

     # 点击确认按钮
     element_transfer_account_result_button.click()

     # 返回到主页面
     self.__back_to_home()

else:
     # 包含正常好友关系和对方账号限制的情况
     print('好友关系正常')
     self.__back_to_home()

最后,点击手机的返回键,一直到微信主界面为止。

def __back_to_home(self):
        """
        回退到主界面
        :return:
        """
        print('准备回退到主界面')
        home_tips = ['微信', '通讯录', '发现', '我']
        while True:
            keyevent('BACK')
            is_home = False

            # 判断是否到达首页
            if self.poco(text=home_tips[0]).exists() and self.poco(text=home_tips[1]).exists() and self.poco(
                    text=home_tips[2]).exists() and self.poco(text=home_tips[3]).exists():
                is_home = True

            if is_home:
                print('已经回到微信首页~')
                break

重复操作上面的步骤,就可以判断出哪些是「僵尸粉」,哪些好友的账号被微信限制,哪些是正常的好友了。


第3步,删除获取到的「僵尸粉」。

拿到上面的僵尸粉数据之后,就可以利用上面的方式进行一系列自动化操作,将这些「僵尸粉」删除掉了。

def del_friend_black(self, weixin_id):
        """
        删除黑名单好友
        :return:
        """
        # 到好友聊天界面
        self.__to_friend_chat_page(weixin_id)

        # 点击聊天界面右上角,进入到好友的详细信息界面
        self.poco(self.id_person_msg_button).click()

        # 点击好友头像
        self.poco(self.id_person_head_url).click()

        # 点击个人名片的右上角,弹出好友操作菜单
        self.poco(self.id_person_manage_menu).click()

        # 查找删除操作栏
        # 注意:对于目前主流的手机,都需要滑动到最底部才能出现【删除】这一操作栏
        self.poco.swipe([0.5, 0.9], [0.5, 0.3], duration=0.2)

        # 点击删除,弹出删除对话框
        self.poco(self.id_person_del, text=self.text_person_del).click()

        # 确定删除好友【确定删除】
        # 界面会直接回到主界面
        self.poco(self.id_person_del_sure, text=self.text_person_del).click()

这样一系列操作之后,「僵尸粉」就被你完美的清理掉了。


是不是很神奇,不错,代码就是这样神奇,想知道Python还有哪些神操作吗?那就关注小编,慢慢听小编一一道来吧!

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码