Форум программистов, компьютерный форум, киберфорум
JavaScript: API
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
5 / 5 / 0
Регистрация: 25.09.2017
Сообщений: 569
Chrome Extension

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

08.02.2025, 23:47. Показов 1553. Ответов 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
Сообщений: 274
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
1286 / 1253 / 187
Регистрация: 21.01.2024
Сообщений: 5,764
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
1286 / 1253 / 187
Регистрация: 21.01.2024
Сообщений: 5,764
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
Сообщений: 274
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
Ответ Создать тему
Новые блоги и статьи
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при изменении наименования справочника
Maks 25.03.2026
Программная отправка письма электронной почты на примере изменения наименования типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 25.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере нетипового документа выдачи шин для спецтехники с табличной частью, разработанного в конфигурации КА2. Номеклатура. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru