谷歌网页插件实现优雅(bushi)刷力扣

本文档记录了一款Chrome插件的开发过程,该插件能自动抓取LeetCode题目的信息,通过Python处理后生成C++代码文件并启动CLion,实现了刷题流程的自动化,节省了程序员的时间。主要涉及浏览器插件与Python程序的通信、文件操作、软件打开及网页内容抓取等技术。
摘要由CSDN通过智能技术生成

基本功能已经完成,源码见https://github.com/hahahaMing/Google_LeetCode_extension/tree/master/nativeMessaging

一、目标

我自己每次刷题的流程是这样的:

  1. 开网页
  2. 开clion
  3. 根据题目名称新建.hpp文件
  4. 复制写好的测试代码框架到hpp文件中
  5. 复制题目自带代码到hpp文件中
  6. 修改main.cpp包含当前hpp

想法就是尽可能在网页端一键做完上述大部分事情,这样每天能够省下好多时间。

二、学习与项目进度

本人没有接触过网页端的编程,需要学习一下。。

2.1 浏览器插件与python程序通信

这里踩了好多坑,踩了3天后实现了浏览器插件与python程序通信。
在这里插入图片描述

接下来的步骤:

  • 控制python程序进行文件创建与修改
  • 控制python程序进行软件打开(可选)
  • 读取力扣网页内容
  • 将网页内容发到python程序中
  • 创建第一个有用的文件
  • 完成剩余步骤
  • 完成软件打开步骤

2.2 控制python程序进行文件创建与修改

 # 接收到"txt"就创建一个名为test.txt的txt文件
 if message == '{"text":"txt"}':
     with open("test.txt",'w',encoding='utf-8')as f:
         f.write("test ok!\n")
         self.log("test creating file ok!")
 
 if message == '{"text":"edit"}':
     with open("test.txt",'a',encoding='utf-8')as f:
         f.write("edit ok!\n")
         self.log("test editing file ok!")

在这里插入图片描述

2.3 控制python程序进行软件打开

if message == '{"text":"open"}':
   # os.startfile(r'E:\Program Files\JetBrains\CLion 2019.3.5\bin\clion64.exe')

   os.startfile(r'C:\Users\15518\Desktop\test.md')
   self.log("opening Typora ok!")

在这里插入图片描述

2.4 读取力扣网页内容

重点在于内嵌脚本
manifest.json

{
  ...,
  "content_scripts": [
    {
      "matches": ["https://leetcode-cn.com/problems/*"],"js": ["contentScript.js"]
    }
  ],
  ...
}

contentScript.js

//window.onload页面加载完毕后立即执行
window.onload = function () {
    var questionTitle = document.querySelector("#question-detail-main-tabs > div.tab-pane__1SHj.css-12hreja-TabContent.e16udao5 > div > div.css-xfm0cl-Container.eugt34i0 > h4 > a").innerText;
    var questionContent = document.querySelector("#question-detail-main-tabs > div.tab-pane__1SHj.css-12hreja-TabContent.e16udao5 > div > div.content__1Y2H > div").innerHTML;
    var codeContent = document.querySelector("div.view-lines").innerText;

    console.log(questionTitle);
    console.log(questionContent);
    console.log(codeContent);

    chrome.runtime.sendMessage({
        greeting: "hello", 
        title: questionTitle, 
        qContent: questionContent, 
        codeText: codeContent 
    }, 
    function (response) {
        console.log(response.farewell);
    });
}

这边有bug,将逻辑改为页面显示后点击按钮进行文字抓取,再做后面的事情。
参考https://developer.chrome.com/docs/extensions/mv3/messaging/

2.5 将网页内容发到python程序中

这里粘贴一个手写的逻辑
在这里插入图片描述
在这里插入图片描述

发送部分:
background.js

  ...
  console.log("sending data...");
  message = {
    "text": "data",
    "title": questionTitle,
    "qContent": questionContent,
    "codeText": codeContent
  };
  port.postMessage(message);
  console.log("Sent message: " + JSON.stringify(message));
  ...

python接收部分

...
 if message.find('data'):
     send_message('{"text":"received"}')
     self.data = message
...

2.6 框架确定

python简化为无窗口模式

import **
# Helper function that sends a message to the webapp.
def send_message(message):
    pass


# Thread that reads messages from the webapp.
def read_thread_func(que):
    while 1:
        pass


class HiddenProcess:
    def __init__(self, que):
        self.data = ''
        pass
	# 处理que中的信息
    def process_messages(self):
        pass
        
    # 自动化处理 data
    def auto_movement(self):
        pass


def Main():
    que = queue.Queue()
    # 处理对象初始化
    hidden_process = HiddenProcess(que)
    # 接收线程开启
    thread = threading.Thread(target=read_thread_func, args=(que,))
    thread.daemon = True
    thread.start()
    # 处理接收信息
    hidden_process.process_messages()
    # 自动化创建文件,打开软件
    hidden_process.auto_movement()
    send_message('{"text":"bye"}')
    sys.exit(0)


if __name__ == '__main__':
    Main()

扩展更改框架为:
manifest.json,background.js,contentScript.js
功能:打开力扣页面植入contentScript.js,之后点击图标在这里插入图片描述
执行余下所有动作(定义在background.js中)。

manifest.json

{
  // Extension ID: knldjmfmopnpolahpmmgbagdohdnhkik
  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB",
  "name": "Native Messaging Example",
  "version": "1.0",
  "manifest_version": 3,
  "description": "Send a message to a native application.",
  "background": {
    "service_worker": "background.js"
  },
  "action": {},
  "content_scripts": [
    {
      "matches": ["https://leetcode-cn.com/problems/*"],"js": ["contentScript.js"]
    }
  ],
  "icons": {
    "16": "/images/get_started16.png",
    "32": "/images/get_started32.png",
    "48": "/images/get_started48.png",
    "128": "/images/get_started128.png"
  },
  "permissions": [
    "nativeMessaging","activeTab"
  ]
}

三、python脚本

这里单拿出来就是因为这部分工作不多但是显得很多。。。
任务:
已经拿到网页的信息

with open('test.json', encoding='utf-8')as fp:
    data_dic = json.load(fp)
    title = data_dic['title']
    qContent = data_dic['qContent']
    codeText = data_dic['codeText']
    codeText = codeText.replace('\xa0', ' ')

现在做后面的事情:

  • 根据题目名称新建.hpp文件
  • 复制写好的测试代码框架到hpp文件中
  • 增加std::
  • 复制题目自带代码到hpp文件中
  • 修改main.cpp包含当前hpp
  • 开clion
  • 新建题目markdown文档
  • 将所需文本写入到文档中(题目,代码框架,代码评价,题解)
  • 打开文档,等待编辑

3.1 代码部分

获取题号:

title_num_str = title.split('.')[0]

得到.hpp文件名

	eng_title = ''
    hpp_title = 'q'
    for i in range(4 - len(title_num_str)):
        hpp_title += '0'
    hpp_title += title_num_str + '_'
    if codeText.find('Solution'):
        eng_title = codeText.split('(')[0].split(' ')[-1]
        hpp_title += eng_title + '.hpp'

写入.hpp文件

hpp_text = '#include"tools.hpp"\n'
        hpp_text += codeText.replace('};', '')
        hpp_text += '\n    void test(){\n        std::cout<<"test start"<<std::endl;\n    }\n};'
        hpp_text = add_std(hpp_text)
        with open(folder_path + '/include/'+hpp_title, 'w', encoding='utf-8')as hpp_f:
            hpp_f.write(hpp_text)

修改 main.cpp

main_text = '#include"'+hpp_title+'"\n'
        with open(main_path, 'r', encoding='utf-8')as main_f:
            old_main_str = main_f.read()
            old_include_len = len(old_main_str.split('\n')[0])
            main_text += old_main_str[old_include_len+1:]
        with open(main_path, 'w', encoding='utf-8')as main_f:
            main_f.write(main_text)

打开clion

os.startfile(r'E:\Program Files\JetBrains\CLion 2019.3.5\bin\clion64.exe')

3.2 文档部分

分类:设计类 or 函数类

设计类
无Solution类
类名为文件名文字部分
包含hpp后直接复制文本到文件
复制test函数框架到文件

函数类
函数名为文件名字部分
复制模板文字到文件
取出函数体后填入相应位置

区分代码

		if codeText.find('Solution') != -1:
            eng_title = codeText.split('Solution')[1].split('(')[0].split(' ')[-1]
            hpp_title += eng_title + '.hpp'
            # .hpp文件文本
            hpp_text = '#include"tools.hpp"\n'
            hpp_text += codeText.replace('};', '')
            hpp_text += '\n    void test(){\n        std::cout<<"test start"<<std::endl;\n    }\n};'
        else:
            eng_title = codeText.split('\nclass ')[1].split(' {')[0]
            hpp_title += eng_title + '.hpp'
            # .hpp文件文本
            hpp_text = '#include"tools.hpp"\n'
            hpp_text += codeText
            hpp_text += 'class Solution {\npublic:\n    void test(){\n        std::cout<<"test start"<<std::endl;\n    }\n};'

整体逻辑无非就是字符串正则查找拼接那些事情,就不多写了,都在前面的仓库里有。

四、整体效果

在这里插入图片描述

五、添加功能

这里添加使用后想到的功能增加与修改。

5.1 使用badge显示插件状态

background.js中某些设置代码如下,这玩意最多设置4个字符。

//设置初始图标前文字为空
chrome.action.setBadgeText({text: ''});
...
  //发送信息,等待py脚本回复连接成功
  chrome.action.setBadgeText({text: 'cnet'});
  ...
    //发送data,等待py回复接收成功
  chrome.action.setBadgeText({text: 'stdt'});
...
  else if (JSON.stringify(message) == '{"text":"bye"}') {
    console.log("close port");
    chrome.action.setBadgeText({text: 'done'});

状态更新频繁一点,这样用户(我)比较安心。
在这里插入图片描述
动图里可以看到,页面刷新后按钮前增加字符got,表示获取页面文字完成;这时点击按钮字符变为stdt,表示正在发送data到.py文件,等待字符变为done表示脚本运行完成,等待文件打开即可。

5.2 提交代码后流程优化

目标:

  1. 提交成功后提取成功的代码与具体的时间内存占用情况
  2. 将信息发送到background.js
  3. 再将信息传递到python插件中,自动生成md文件(这步可以尝试自动完成,也可以手动点击工具栏按钮)

5.3 生成代码文件时自动填写测试用例

目标:根据函数体输入输出在test()函数中填写输入的定义与输出的语句。

新电脑适配debug

  1. leecode网站改版,这边更新nativeMessaging\app\contentScript.js使js搜索正常
  2. 记住一定要更新好代码再按按钮
  3. 点击后效果为打开了vscode中的文件,证明host可以通信但是通信方式不对
  4. 默认打开方式设置为vscode了,所以会打开vscode
  5. 后面是字符串编码问题和回车去留问题,解决后可以正常使用

余下要完成的任务:

  • 代码规范化(哪不顺眼改哪里)
  • bug调试(随着做题,不断发现bug)
  • 编写使用文档(虽然没啥人有这个需求,但是善始善终么)
  • 程序美化(换图标,github主页美化。。。)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值