5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
Chrome Extension

Можно ли при разработке расширения для Chrome запускать код, взаимодействующий с DOM в фоновом режиме

08.02.2025, 23:47. Показов 1561. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Интересно, будет ли результат в виде изменения DOM от такой реализации и вообще можно ли так делать или я что-то не понял. Пример взял отсюда:

https://developer.chrome.com/d... tInjection

вот пример по ссылке:
JavaScript
1
2
3
4
5
6
7
8
9
function getTabId() { ... }
function getTitle() { return document.title; }
 
chrome.scripting
    .executeScript({
      target : {tabId : getTabId()},
      func : getTitle,
    })
    .then(() => console.log("injected a function"));
... и вроде, это как будто-то бы ТАК можно, почему-то DOM изменить не могу, если событие срабатывает в background.js, ошибок в консоли нет.

У меня пример посложнее - вместо getTitle код изменяет DOM, при этом изменения не происходит.

Как у меня - примерно вот так:

background.js
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function getTitle() { 
     const btn = document.createElement(
        "button", {
            "class": "btn-style"
        }
    )
    const pageHeader = document.body
    pageHeader.appendChild(btn)
}
 
async function change(tab){
 
   chrome.scripting
      .executeScript({
           target : {tabId : tab.id},
           func : getTitle,
       })
      .then(() => console.log("injected a function"));
 
}
 
chrome.tabs.onUpdated.addListener(async (tabId, currentTab, tab) => {
    console.log(`Updated, tab.id - ${tab.id}`)
    await change(tab)
})
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.02.2025, 23:47
Ответы с готовыми решениями:

Можно ли обрабатывать страницы сайта используя расширения для google chrome?
Привет. Суть такая, есть сайт, и было бы неплохо как-то автоматизировать некоторые действия на нем, например, пройтись по некоторым...

Как заставить работать кликер на С++ в фоновом режиме в фоновом окне?
есть игра http://www.csie.ntu.edu.tw/~b01902112/9007199254740992/ написал код #include <windows.h> int main (int argc, char **...

Можно ли, чтобы программа сама, в фоновом режиме, работала в браузере?
Есть задумки по-поводу одной программы. Она должна сама работать в браузере без моей помощи. Может какая-то библиотечка нужна? Если это...

10
 Аватар для MallSerg
91 / 58 / 14
Регистрация: 16.11.2018
Сообщений: 273
09.02.2025, 01:46
>> Можно ли ..
Можно только осторожно.

Параметр функции .executeScript ... сериализуется в JSON и передается табу там из него создается объект свойство которого
func вызывается как функция.

Что возвращает?
JavaScript
1
console.log( JSON.stringify({ target : {tabId : tab.id}, func : getTitle, }) )
Пример расширения
Парсинг сайта: как получить код страницы в память
1
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
09.02.2025, 03:21  [ТС]
Цитата Сообщение от MallSerg Посмотреть сообщение
console.log( JSON.stringify({ target : {tabId : tab.id}, func : getTitle, }) )
всё, кроме func почему-то, даже пробовал самую простую задавать:

JavaScript
1
2
3
function getTitle(){
     return true
}
0
 Аватар для voraa
1289 / 1263 / 187
Регистрация: 21.01.2024
Сообщений: 5,807
09.02.2025, 09:55
Цитата Сообщение от Alex_py Посмотреть сообщение
всё, кроме func почему-то
Ну потому, что функции не сериализуются в JSON
1
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
09.02.2025, 17:58  [ТС]
Цитата Сообщение от voraa Посмотреть сообщение
Ну потому, что функции не сериализуются в JSON
Тогда, получается это пример нерабочего кода, который самый первый в стартовом посте? Почему вообще google приводит заранее нерабочий код, абсурд какой-то =)
0
 Аватар для voraa
1289 / 1263 / 187
Регистрация: 21.01.2024
Сообщений: 5,807
09.02.2025, 18:08
Вот так вот
JavaScript
1
console.log( JSON.stringify({ target : {tabId : tab.id}, func : getTitle, }) )
Нельзя. Потому, что функции не сериализуются в JSON.

А где сказано, что параметр executeScript должен сериализоваться, я не нашел.
1
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
09.02.2025, 23:49  [ТС]
Цитата Сообщение от voraa Посмотреть сообщение
А где сказано, что параметр executeScript должен сериализоваться, я не нашел.
Может, именно для скриптов, зарегистрированных в "background" это не работает, но где работает этот шаблон непонятно.

Получилось так:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
background.js:
 
 
const urlPatterns = [
    'https://steamcommunity.com/profiles/',
]
 
async function addMenuChrome(tab){
    var draftMenu = false
 
    const [currentTab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
    for (let urlPattern of urlPatterns){
        if (currentTab && currentTab.url.startsWith(urlPattern)){
            draftMenu = true
            break
        }
    } 
 
    if (!currentTab){
        draftMenu = true
    }
 
    let tabId = tab.tabId || tab.id
   
    const injectObject = { 
        files: [ "scripts/content.js" ],
        target : { allFrames: true, tabId :  tabId }
    }
    const asJson = JSON.stringify(injectObject)
    console.log(`InjectObject: ${asJson}`)
 
    if (draftMenu){
        try {
            chrome.scripting.executeScript(
                injectObject
            ).then(injectionResults => {
                for (const {frameId, result} of injectionResults){
                    console.log(`Frame: ${frameId}, result: ${result}`)
                }
            })
        }
        catch (error){
            console.log(`An error occur at draft menu. Details: ${error}`)
        }
    }
}
 
 
chrome.tabs.onUpdated.addListener(async (tabId, currentTab, tab) => {
 
    await addMenuChrome(tab)
 
})
Я правда не знаю, лучше ли так, как-то вызов executeScript не может сериализовать функцию, превратив её в абсолютную ссылку, зато может модуль. Страницы иногда почему-то прогружаются теперь долго и изменений DOM не видно. Со стороны пользователя не очевидно, что расширение работает, просто нужно перезагружать страницу, пока кнопка не появится...

Помимо всего этого, я не понимаю, почему кнопка появляется только при перезагрузке страницы по кнопке браузера "обновить страницу". Событие срабатывает также, когда нажимаются кнопки горизонтального меню внутри страницы (документ меняется только в нижних блоках под горизонтальным меню, сам блок, куда добавляется кнопка остаётся как есть). Это тоже приводит к срабатыванию "chrome.tabs.onUpdated", но кнопка не добавляется после такого. Также кнопка исчезает, если нажать F12, открывая инструменты разработчика. Какие-то "хитрости" здесь должны быть.

Интересно, что после того как обновляю страницу по кнопке "обновить", то в консоли убеждаюсь, что метод был вызван столько же раз, сколько я нажимал на вкладки меню. Почему кнопка не добавляется ...

Добавлено через 1 час 5 минут
Событие дважды срабатывает, кнопка два раза добавляется после прогрузки документа. Магия какая-то...

Добавлено через 8 минут
Не знаю что такого в манифестации, директория "scripts/modules/" содержит только скрипт с реализованным методом, который ни к какому событию не привязан.

JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
    "name": "last-seen-approx",
    "version": "0.0.0",
    "manifest_version": 3,
    "icons": {
        "16": "/assets/images/logo_very_small.png",
        "32": "/assets/images/logo_very_small.png",
        "48": "/assets/images/browser_icon.jpeg",
        "96": "/assets/images/logo_big.jpg"
    },
    "background": {
        "service_worker": "scripts/background.js",
        "type": "module" 
    },
    "web_accessible_resources": [
        {
            "matches": [
                "https://www.steamcommunity.com/*"
            ],
            "resources": [
                "scripts/modules/*"
            ]
        }
    ],
    "action": {
        "default_icon": {
            "16": "/assets/images/browser_icon.jpeg",
            "32": "/assets/images/logo_very_small.png",
            "48": "/assets/images/browser_icon.jpeg",
            "96": "/assets/images/logo_big.jpg"
        },
        "default_title": "Last seen approx"
    },
    "permissions": [
        "activeTab",
        "scripting",
        "tabs"
    ],
    "host_permissions": [
        "https://www.steamcommunity.com/profiles/*"
    ]
}
Добавлено через 19 минут
Такое впечатление, что страницу обновляю дважды одновременно, так же не может быть... в системе отладки гугл что-то поломалось.
0
 Аватар для MallSerg
91 / 58 / 14
Регистрация: 16.11.2018
Сообщений: 273
10.02.2025, 01:18
Цитата Сообщение от voraa Посмотреть сообщение
А где сказано, что параметр executeScript должен сериализоваться, я не нашел.
Топик стартер далл ссылку.
Первые предложения по этой ссылке.
"
The arguments to pass to the provided function. This is only valid if the func parameter is specified. These arguments must be JSON-serializable.
"

Чуть ниже есть описание для свойcтва func
"
func
void optional
Chrome 92+
A JavaScript function to inject. This function will be serialized, and then deserialized for injection. This means that any bound parameters and execution context will be lost. Exactly one of files or func must be specified.

The func function looks like:
() => {...}

"
Это просто цитирование справки из приведенной ссылки.
1
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
10.02.2025, 05:13  [ТС]
Цитата Сообщение от Alex_py Посмотреть сообщение
Такое впечатление, что страницу обновляю дважды одновременно, так же не может быть... в системе отладки гугл что-то поломалось.
С этим справился, добавив перед вызовом метода проверку на состояние готовности документа.

Цитата Сообщение от MallSerg Посмотреть сообщение
This means that any bound parameters and execution context will be lost. Exactly one of files or func must be specified.
вот для файлов работает

Цитата Сообщение от Alex_py Посмотреть сообщение
Помимо всего этого, я не понимаю, почему кнопка появляется только при перезагрузке страницы по кнопке браузера "обновить страницу".
а вот это непонятно, я использую Mutation, чтобы определить когда появится нужный элемент в DOM, чтобы добавить в него кнопку.

Когда перезагрузка страницы происходит при нажатии на вкладку меню, кнопка не появляется, в консоли видно, что событие перезагрузки срабатывает, а стоит перезагрузить страницу из функции браузера Chrome - добавляется. И по нажатию на вкладку вот эта штуковина не срабатывает (строка 34 кода js листинга 7-го поста):

JavaScript
1
chrome.scripting.executeScript
Я вижу выполнение, только после того как обновлю страницу через функции браузера.
Странный эффект.
0
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
10.02.2025, 23:30  [ТС]
Ну я так понимаю, всё дело в задании target.

JavaScript
1
2
3
4
target : { 
            allFrames: true, 
            tabId :  tabId
        }
id вкладки tab не меняется, оно то же, просто страница обновляется по нажатию кнопки меню, так что заставляет не выполниться эту штуковину:

JavaScript
1
chrome.scripting.executeScript
Такое впечатление, что js забуксовал на этой инструкции и только после обновления страницы через штатную функцию браузера, выполнит код, - по выводу консоли.
0
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
12.02.2025, 02:06  [ТС]
background.js

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
async function addMenuChrome(tab){
    var draftMenu = false
 
    for (let urlPattern of urlPatterns){
        if (tab.url.startsWith(urlPattern)){
            draftMenu = true
            break
        }
    } 
 
    let tabId = tab.tabId || tab.id
 
    let allFrames = false
    let frameIds = tab.frameId !== undefined ? [tab.frameId] : []
    
    let target = {
        tabId: tabId
    }
 
    if (frameIds.length){
        target.frameIds = frameIds
    }
 
    const injectObject = { 
        files: [ "scripts/content.js" ],
        target : target
    }
 
    const asJson = JSON.stringify(injectObject)
    console.log(`InjectObject: ${asJson}`)
    console.log(`draftMenu: ${draftMenu}`)
 
    if (draftMenu){
        try {
            chrome.scripting.executeScript(
                injectObject
            ).then(injectionResults => {
                for (const {frameId, result} of injectionResults){
                    console.log(`Frame: ${frameId}, result: ${result}`)
                }
            }).catch((error) => { console.log(`An error occur at draft menu. Details: ${error}`) })
        }
        catch (error){
            console.log(`An error occur at draft menu. Details: ${error}`)
        }
    }
    
}
 
 
chrome.tabs.onUpdated.addListener(async (tabId, currentTab, tab) => {
    console.log(`//////Props of current tab: ${Object.keys(currentTab)}//////`)
    console.log(`Updated, tabId - ${tabId}`)
    console.log(`current url: ${currentTab.url}`)
    console.log(`status: ${currentTab.status}`)
    console.log(`tab.id: ${tab.id}`)
    console.log(`tab.active: ${tab.active}`)
    console.log(`tab.lastAccessed: ${tab.lastAccessed}`)
    console.log(`tab.url: ${tab.url}`)
    console.log(`tab.windowId: ${tab.windowId}`)
 
    if (tab.url !== undefined && currentTab.status == "complete"){
        console.log("BEGIN ADD MENU...")
        await addMenuChrome(tab)
    }
})
Справка по методу executeScript():

Цитата:

Внедряет скрипт в целевой контекст. По умолчанию скрипт будет запущен в document_idle или немедленно, если страница уже загружена. Если установлено свойство injectImmediately, скрипт будет внедрен без ожидания, даже если страница не завершила загрузку. Если скрипт оценивается как обещание, браузер будет ждать, пока обещание не будет выполнено, и вернет результирующее значение.

"document_idle" В-общем-то неважно, загрузится ли документ окончательно, я в подключаемом скрипте всё-равно отлавливаю изменения DOM, что позволяет точно обнаружить нужный элемент, куда я хочу вставить, то (кнопка) что нужно. Если бы что-то пошло не так - я бы увидел ошибки.

Просто не запускается инструкция: chrome.scripting.executeScript. И такой симптом наблюдается для текущей активной вкладки, когда событие обновления происходит по нажатию на кнопку горизонтального меню в этой странице. Событие происходит, в консоли я вижу соответствующий вывод, код выполняется до chrome.scripting.executeScript в вызванном методе addMenuChrome и всё, дальше ничего не происходит, пока не обновишь страницу вручную через стандартную функцию браузера.

Документация говорит, что этот механизм аналогичен реализации через content_scripts, для этого правда события можно задать в manifest.json, когда нужно внедрять скрипт. Так тоже пробовал - абсолютно тот же симптом.


И учитывая все эти изложенные симптомы, я прихожу к выводу, что скрипт через инструкцию chrome.scripting.executeScript для каждого активного окна, внедряется и отрабатывает единожды при обновлении страницы через стандартную функцию браузера или при переходе по url, и больше эта инструкция в коде не выполняется, если после этого происходит некое событие.

Добавлено через 3 часа 41 минуту
Я заблуждался, скорее всего, как я полагаю, это всё из-за параллельной прогрузки других ресурсов. Структура страницы сложная, поэтому когда остальные фреймы ещё не прогрузились и запущена процедура добавления элемента (кнопки, чего угодно там) для текущей вкладки (главный фрейм как я полагаю сюда относится), это влияет на добавление элемента в целевой блок. То есть, до тех пор пока не прогрузились остальные ресурсы документ сбрасывается, инициализируется заново и все действия по добавлению сводятся на нет и я это вижу, что элемент исчезает.

Как-то всё очень запутанно, с другой стороны, почему составные фреймы влияют на тот, куда они входят. У меня, как видно из кода на 62-й строке идёт проверка окончательной загрузки вкладки. Остальные фреймы, которые в неё входят загружаются следом (исходя из вывода в консоль).

Пока не знаю что с этим делать и как это контролировать...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.02.2025, 02:06
Помогаю со студенческими работами здесь

Воспроизведение звука при нажатии на клавиши, при работе программы в фоновом режиме
Нужно написать программу, воспроизводящую звук при нажатии на любую клавишу. Только нужно что бы программа работала в фоновом режиме, т.е....

Встраиваемый код и расширения chrome
Добрый день. Знакомлюсь с созданием chrom расширений и столкнулся с непониманием принципа расширений. Задача: По нажатию на кнопку с...

Самопроизвольный запуск Word 2010 в фоновом режиме при загрузке Windows 7
Добрый день всем! Возникла проблема, поиски решения на просторах интернета и форума (возможно не нашёл) результатов не принесли. ...

[WPF] При нажатии на крестик окно не закрывается, а остается в фоновом режиме
Пишу игру на c# в wpf. В форме есть кнопки для закрытия программы, если нажать на них, то программа закрывается. Но если закрывать их...

Воспроизвести звук в фоновом режиме. Приложение для ходьбы
Создаю приложение для ходьбы. Не могу решить одну проблему. Сначала объясню суть работы приложения. Есть программа тренировок для ходьбы из...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

Новые блоги и статьи
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита "ПричинаСписания". . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Программное заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru