Giter Site home page Giter Site logo

ghost-cursor's Introduction

Ghost Cursor

Generate realistic, human-like mouse movement data between coordinates or navigate between elements with puppeteer like the definitely-not-robot you are.

Oh yeah? Could a robot do this?

Installation

yarn add ghost-cursor

or with npm

npm install ghost-cursor

Usage

Generating movement data between 2 coordinates.

import { path } from "ghost-cursor"

const from = { x: 100, y: 100 }
const to = { x: 600, y: 700 }

const route = path(from, to)

/**
 * [
 *   { x: 100, y: 100 },
 *   { x: 108.75573501957051, y: 102.83608396351725 },
 *   { x: 117.54686481838543, y: 106.20019239793275 },
 *   { x: 126.3749821408895, y: 110.08364505509256 },
 *   { x: 135.24167973152743, y: 114.47776168684264 }
 *   ... and so on
 * ]
 */

Generating movement data between 2 coordinates with timestamps.

import { path } from "ghost-cursor"

const from = { x: 100, y: 100 }
const to = { x: 600, y: 700 }

const route = path(from, to, { useTimestamps: true })

/**
 * [
 *   { x: 100, y: 100, timestamp: 1711850430643 },
 *   { x: 114.78071695023473, y: 97.52340709495319, timestamp: 1711850430697 },
 *   { x: 129.1362373468682, y: 96.60141853603243, timestamp: 1711850430749 },
 *   { x: 143.09468422606352, y: 97.18676354029148, timestamp: 1711850430799 },
 *   { x: 156.68418062398405, y: 99.23217132478408, timestamp: 1711850430848 },
 *   ... and so on
 * ]
 */

Usage with puppeteer:

import { createCursor } from "ghost-cursor"
import puppeteer from "puppeteer"

const run = async (url) => {
  const selector = "#sign-up button"
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage()
  const cursor = createCursor(page)
  await page.goto(url)
  await page.waitForSelector(selector)
  await cursor.click(selector)
  // shorthand for
  // await cursor.move(selector)
  // await cursor.click()
}

Puppeteer-specific behavior

  • cursor.move() will automatically overshoot or slightly miss and re-adjust for elements that are too far away from the cursor's starting point.
  • When moving over objects, a random coordinate that's within the element will be selected instead of hovering over the exact center of the element.
  • The speed of the mouse will take the distance and the size of the element you're clicking on into account.

ghost-cursor in action

Ghost cursor in action on a form

Methods

createCursor(page: puppeteer.Page, start?: Vector, performRandomMoves?: boolean, defaultOptions?: DefaultOptions): GhostCursor

Creates the ghost cursor. Returns cursor action functions.

  • page: Puppeteer page.
  • start (optional): Cursor start position. Default is { x: 0, y: 0 }.
  • performRandomMoves (optional): Initially perform random movements. Default is false.
  • defaultOptions (optional): Set custom default options for click, move, moveTo, and randomMove functions. Default values are described below.

toggleRandomMove(random: boolean): void

Toggles random mouse movements on or off.

click(selector?: string | ElementHandle, options?: ClickOptions): Promise<void>

Simulates a mouse click at the specified selector or element.

  • selector (optional): CSS selector or ElementHandle to identify the target element.
  • options (optional): Additional options for clicking.
    • hesitate (number): Delay before initiating the click action in milliseconds. Default is 0.
    • waitForClick (number): Delay between mousedown and mouseup in milliseconds. Default is 0.
    • moveDelay (number): Delay after moving the mouse in milliseconds. Default is 2000. If randomizeMoveDelay=true, delay is randomized from 0 to moveDelay.
    • randomizeMoveDelay (boolean): Randomize delay between actions from 0 to moveDelay. Default is true.

move(selector: string | ElementHandle, options?: MoveOptions): Promise<void>

Moves the mouse to the specified selector or element.

  • selector: CSS selector or ElementHandle to identify the target element.
  • options (optional): Additional options for moving.
    • paddingPercentage (number): Percentage of padding to be added inside the element. Default is 0 (may move to anywhere within the element). 100 will always move to center of element.
    • waitForSelector (number): Time to wait for the selector to appear in milliseconds. Default is to not wait for selector.
    • moveDelay (number): Delay after moving the mouse in milliseconds. Default is 0. If randomizeMoveDelay=true, delay is randomized from 0 to moveDelay.
    • randomizeMoveDelay (boolean): Randomize delay between actions from 0 to moveDelay. Default is true.
    • maxTries (number): Maximum number of attempts to mouse-over the element. Default is 10.
    • moveSpeed (number): Speed of mouse movement. Default is random.
    • overshootThreshold (number): Distance from current location to destination that triggers overshoot to occur. (Below this distance, no overshoot will occur). Default is 500.

moveTo(destination: Vector, options?: MoveToOptions): Promise<void>

Moves the mouse to the specified destination point.

  • destination: An object with x and y coordinates representing the target position. For example, { x: 500, y: 300 }.
  • options (optional): Additional options for moving.
    • moveSpeed (number): Speed of mouse movement. Default is random.
    • moveDelay (number): Delay after moving the mouse in milliseconds. Default is 0. If randomizeMoveDelay=true, delay is randomized from 0 to moveDelay.
    • randomizeMoveDelay (boolean): Randomize delay between actions from 0 to moveDelay. Default is true.

getLocation(): Vector

Get current location of the cursor.

Other Utility Methods

installMouseHelper(page: Page): Promise<void>

Installs a mouse helper on the page. Makes pointer visible. Use for debugging only.

getRandomPagePoint(page: Page): Promise<Vector>

Gets a random point on the browser window.

path(point: Vector, target: Vector, options?: number | PathOptions): Vector[] | TimedVector[]

Generates a set of points for mouse movement between two coordinates.

  • point: Starting point of the movement.
  • target: Ending point of the movement.
  • options (optional): Additional options for generating the path. Can also be a number which will set spreadOverride.
    • spreadOverride (number): Override the spread of the generated path.
    • moveSpeed (number): Speed of mouse movement. Default is random.
    • useTimestamps (boolean): Generate timestamps for each point based on the trapezoidal rule.

How does it work

Bezier curves do almost all the work here. They let us create an infinite amount of curves between any 2 points we want and they look quite human-like. (At least moreso than alternatives like perlin or simplex noise)

The magic comes from being able to set multiple points for the curve to go through. This is done by picking 2 coordinates randomly in a limited area above and under the curve.

However, we don't want wonky looking cubic curves when using this method because nobody really moves their mouse that way, so only one side of the line is picked when generating random points.

When calculating how fast the mouse should be moving we use Fitts's Law to determine the amount of points we should be returning relative to the width of the element being clicked on and the distance between the mouse and the object.

To turn on logging, please set your DEBUG env variable like so:

  • OSX: DEBUG="ghost-cursor:*"
  • Linux: DEBUG="ghost-cursor:*"
  • Windows CMD: set DEBUG=ghost-cursor:*
  • Windows PowerShell: $env:DEBUG = "ghost-cursor:*"

ghost-cursor's People

Contributors

alvinlys avatar androbin avatar aw1875 avatar berstend avatar brunogaspar avatar bvandercar-vt avatar dependabot[bot] avatar fdelmazo avatar garyanikin avatar kbourro avatar lublak avatar nevgup avatar niek avatar nintendoengineer avatar renardudezert avatar rviar avatar sharifpour avatar smartarray avatar thegp avatar vladtreny avatar xetera avatar zeke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ghost-cursor's Issues

Start position is always 0,0

The Start position of cursor.move or click is always 0,0. I want to randomize this, where can I set that?

I tried to page.mouse.move to a random coordinates, but since I am scrolling. The movement done by page.mouse is useless and the cursor spawns back to 0,0.

Protocol error (DOM.scrollIntoViewIfNeeded): Cannot find context with specified id

Hi,
Thanks for making this awesome module. I was using it to click an object inside of an iframe. Here is the code:

"ghost-cursor": "^1.1.11",
"puppeteer": "^14.3.0",
"puppeteer-extra": "^3.2.3",
"puppeteer-extra-plugin-stealth": "^2.9.0",
"user-agents": "^1.0.1017"
import { setTimeout as sleep } from 'timers/promises';
import UserAgent from 'user-agents';
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import { createCursor } from 'ghost-cursor';

const userAgent = new UserAgent({ deviceCategory: 'desktop' }).toString();

const browser = await puppeteer.use(StealthPlugin()).launch({
  headless: false,
  ignoreHTTPSErrors: true,
  args: [
    '--disable-gpu',
    '--disable-extensions',
    '--disable-dev-shm-usage',
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--no-first-run',
    '--no-zygote',
    '--single-process',
    '--disable-infobars',
    '--window-position=0,0',
    '--ignore-certifcate-errors',
    '--ignore-certifcate-errors-spki-list',
  ],
});
let page = await browser.newPage();
const cursor = createCursor(page);

await page.setUserAgent(userAgent);

await page.goto('https://www.hermes.cn');
const iFrame = await page.waitForSelector('iframe[src^="https://geo.captcha-delivery.com"]');
const frame = await iFrame.contentFrame();
const clickHandle = await frame.waitForSelector('.geetest_radar_tip');
await cursor.click(clickHandle);

await sleep(30000);

However there's an error:

Falling back to JS scroll method ProtocolError: Protocol error (DOM.scrollIntoViewIfNeeded): Cannot find context with specified id
    at /var/www/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:230:24
    at new Promise (<anonymous>)
    at CDPSession.send (/var/www/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:226:16)
    at next (/var/www/node_modules/puppeteer-extra-plugin-stealth/evasions/sourceurl/index.js:32:41)
    at CDPSession.send (/var/www/node_modules/node_modules/puppeteer-extra-plugin-stealth/evasions/sourceurl/index.js:57:18)
    at Object.<anonymous> (/var/www/node_modules/node_modules/ghost-cursor/lib/spoof.js:426:53)
    at step (/var/www/node_modules/node_modules/ghost-cursor/lib/spoof.js:44:23)
    at Object.next (/var/www/node_modules/node_modules/ghost-cursor/lib/spoof.js:25:53)
    at /var/www/node_modules/node_modules/ghost-cursor/lib/spoof.js:19:71
    at new Promise (<anonymous>) {
  originalMessage: 'Cannot find context with specified id'
}

Actually the click event is triggered, but it seems that there's something wrong with the scroll. Is there any way to fix it?

How to increase mouse speed for moveTo method?

await cursor.moveTo(await ghostCursor.getRandomPagePoint(page)); This takes extremely long for the mouse to move to the point on page. How can i increase the speed or what are my other options to make the cursor move faster to a specific vector point because cursor.move() method only accepts selector arguments and not the specific vector point

Generating a route using path() which includes overshoot coordinates

I really like the implementation of this project but I'm not keen on using Puppeteer to automate the browser since many companies claim to be able to detect its use. The path function seems very useful for generating the necessary coordinates for mouse movement, are there any plans to include the overshoot functionality?

Separate vertical and horizontal padding

First of all, many thanks for creating this package! It has really helped my project a lot.
I am using the cursor mainly for clicking tens of elements on a page in succession and I have noticed that using paddingPercentage produces several misclicks. After watching puppeteer running without headless mode I suspect that the reason is that the cursor clicks too low or too high vertically.
So my feature request is to introduce separate vertical and horizontal padding percentages, something like:

..., paddingPercentage: {vertical: 5, horizontal: 10} 

or

..., paddingPercentage: [5,10]

SyntaxError: Cannot use import statement outside a module

Im trying to run this code:
`import { createCursor } from "ghost-cursor"
import puppeteer from "puppeteer"

const run = async (url) => {
const selector = "#sign-up button"
const browser = await puppeteer.launch({ headless: false });
const page = browser.newPage()
const cursor = createCursor(page)
await page.goto(url)
await page.waitForSelector(selector)
await cursor.click(selector)
// shorthand for
// await cursor.move(selector)
// await cursor.click()
}

run(https://www.nike.com/de/login);`

But I'm getting this error the whole time:
(node:3984) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. (Usenode --trace-warnings ...` to show where the warning was created)
C:\Users\David\Desktop\learn_js-Kopie.js:1
import { createCursor } from "ghost-cursor"
^^^^^^

SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:1001:16)
at Module._compile (internal/modules/cjs/loader.js:1049:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
at internal/main/run_main_module.js:17:47
`

clickCount support

hey guys, thanks for the awesome module.

Please support click optinos like that:

  const cursor = createCursor(page);

  await cursor.click('.someClass', {clickCount: 3})

Thanks

Cursor Movement and Clicking Not Working For Any Selectors

This is the example of the error that I get

Warning: could not move mouse, error message: ProtocolError: Protocol error (Input.dispatchMouseEvent): Invalid parameter
Invalid parameters

I can confirm that the selectors I am using are valid. I haven't been getting this problem only until recently. Haven't changed anything up so I am a bit confused why it is happening

Wrong element clicked for Firefox

Hi,

I'm using the click functionality and it does not work well for Firefox, usually another element below the actual target one gets clicked.
It can be reproduced by this script

const puppeteer = require('puppeteer');
const { createCursor } = require("ghost-cursor");

(async () => {
    const browser = await puppeteer.launch({ product: "firefox", headless: false });
    const page = await browser.newPage();
    const cursor = createCursor(page);
    await page.goto("https://httpbin.org/");
    const selector = "#operations-tag-HTTP_Methods";
    await page.waitForSelector(selector);
    await cursor.click(selector);
})();

The intention of this script is to click the "HTTP Methods" section but it was not clicked, instead, another section between "Cookies" to "Anything" got clicked.
There is a debug level logging indicating it was using the JS scroll fallback which seems to be relevant to the issue.

Falling back to JS scroll method ProtocolError: Protocol error (DOM.scrollIntoViewIfNeeded): DOM.scrollIntoViewIfNeeded RemoteAgentError@chrome://remote/content/cdp/Error.jsm:29:5
UnknownMethodError@chrome://remote/content/cdp/Error.jsm:112:7

Version: 1.1.8

its not work

i was installed this but its not work

anybody help with this ?

i have 3 years experince with puppeteer

Random Heap overflows

Hello, first of all thanks for the great package, it works wonderfully.

I think I'm having a strange issue and suspect the root may be this package. I am using puppeteer to crawl through sites so I'm doing the typical breath-first crawl where I essentially crawl in a loop, go from one page to the next by clicking in the same session. After a few hours of this happening, without fail, the crawler crashes with a heap OOM issue. I'm adding it below.

I use

const cursor = createCursor(page);  
await cursor.click(linkToClick);

What's strange is that there are no other errors and node's own heap seems totally stable up until this happens, unless I'm missing how to accurately calculate this. I'm using process.memoryUsage(); to get the info out.

I am working on a minimal repro now, but it takes hours to make it happen so I'll be back. Just posting this in case anyone has had this experience before.

Thanks in advance for any advice.

[18:0x49a3f30]   142189 ms: Scavenge 1031.6 (1069.2) -> 1031.6 (1069.2) MB, 93.2 / 0.0 ms  (average mu = 0.997, current mu = 0.800) allocation failure
[18:0x49a3f30]   144223 ms: Mark-sweep 1605.4 (1643.0) -> 991.0 (1029.1) MB, 610.5 / 0.0 ms  (+ 0.8 ms in 1 steps since start of marking, biggest step 0.8 ms, walltime since start of marking 2034 ms) (average mu = 0.978, current mu = 0.828) allocation fai
<--- JS stacktrace --->

==== JS stack trace =========================================
    0: ExitFrame [pc: 0x140de99]

Security context: 0x31dfc86808d1 <JSObject>

    1: getLUT [0x25054c602cc9] [/node_modules/bezier-js/lib/bezier.js:~249] [pc=0x9b6638e9d17](this=0x1f5332321ba1 <Bezier map = 0x337528555069>,0x05e0a6fbd7d1 <HeapNumber inf>)
    2: path(aka path) [0x1a1490b50791] [/node_modules/ghost-cursor/lib/spoof.js:187] [bytecode=0x153fbe7bb171 offset=164](this=0x2429bc0804b1 <undefined>,0x1f5332321cb1 <Object map = 0x1f...

FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
 1: 0xa1a640 node::Abort() [node]
 2: 0xa1aa4c node::OnFatalError(char const*, char const*) [node]
 3: 0xb9a68e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xb9aa09 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xd57c85  [node]
 6: 0xd2fc70 v8::internal::Factory::NewUninitializedFixedArray(int, v8::internal::AllocationType) [node]
 7: 0xe9f161  [node]
 8: 0xe9f410  [node]
 9: 0x1047ddb v8::internal::Runtime_GrowArrayElements(int, unsigned long*, v8::internal::Isolate*) [node]
10: 0x140de99  [node]
Aborted (core dumped)
npm ERR! code ELIFECYCLE
npm ERR! errno 134
npm ERR! [email protected] start: `node crawler.js`
npm ERR! Exit status 134
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR!     /home/pptruser/.npm/_logs/2021-04-26T19_39_00_063Z-debug.log

Cursor seems to overshoot a little too much sometimes

I have noticed that occasionally the cursor will overshoot a little too much and not click the element. This is causing puppeteer's to accidentally navigate to the wrong page.

Is the a way to adjust the overshoot and make it smaller?

Node does not have a layout object

Version: 1.1.8

Falling back to JS scroll method ProtocolError: Protocol error (DOM.scrollIntoViewIfNeeded): Node does not have a layout object
at /Users/xxx/Project/new-ali/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:230:24
at new Promise ()
at CDPSession.send (/Users/xxx/Project/new-ali/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:226:16)
at next (/Users/xxx/Project/new-ali/node_modules/puppeteer-extra-plugin-stealth/evasions/sourceurl/index.js:32:41)
at CDPSession.send (/Users/xxx/Project/new-ali/node_modules/puppeteer-extra-plugin-stealth/evasions/sourceurl/index.js:57:18)
at Object. (/Users/xxx/Project/new-ali/node_modules/ghost-cursor/lib/spoof.js:426:53)
at step (/Users/xxx/Project/new-ali/node_modules/ghost-cursor/lib/spoof.js:44:23)
at Object.next (/Users/xxx/Project/new-ali/node_modules/ghost-cursor/lib/spoof.js:25:53)
at fulfilled (/Users/xxx/Project/new-ali/node_modules/ghost-cursor/lib/spoof.js:16:58) {
originalMessage: 'Node does not have a layout object'
}

it works! but the pointer is not visible

Hi @Xetera, @Niek, @kbourro, @garyanikin, and everyone else who's worked on this nifty little package.

I just gave this a try, and the clicking works, but I don't actually see a visible mouse pointer. I can see hover states, and clicking the link does indeed navigate to a new page, but no 🐁👀

Am I doing something wrong?

My code

import puppeteer from 'puppeteer'
import { createCursor } from 'ghost-cursor'
const url = 'https://github.com/nodejs/node/discussions'

async function main () {
  const browser = await puppeteer.launch({ headless: false, defaultViewport: null })
  const pages = await browser.pages()
  const page = pages[0]
  await page.goto(url)
  const selector = 'a[href="/nodejs/node/discussions/36430"]'
  await page.waitForSelector(selector)
  const cursor = createCursor(page)
  // await cursor.click(selector)
  await cursor.move(selector)
  await cursor.click()
  setTimeout(async () => {
    await browser.close()
  }, 3000)
}

main()

My environment

$ node --version
v16.3.0

$ npm ls puppeteer
discussions-translation-screencast@ /Users/z/Desktop/discussions-translation-screencast
└── [email protected]

$ uname -a
Darwin Zekes-MacBook-Pro.local 19.6.0 Darwin Kernel Version 19.6.0: Mon Apr 12 20:57:45 PDT 2021; root:xnu-6153.141.28.1~1/RELEASE_X86_64 x86_64

Ghost Cursor with puppeteer-cluster

I'm trying to use ghost cursor with cluster and it is having trouble moving the mouse.

My code:

await cluster.task(async ({ page, data: { url } }) => 
    {
        //Randomize viewport size
        await page.setViewport({
            width: 1920 + Math.floor(Math.random() * 100),
            height: 1080 + Math.floor(Math.random() * 100),
            deviceScaleFactor: 1,
            hasTouch: false,
            isLandscape: false,
            isMobile: false,
        });

        //Skip images/styles/fonts loading for performance
        await page.setRequestInterception(true);
        page.on('request', (req) =>
        {
            if (/*req.resourceType() == 'stylesheet' ||*/ req.resourceType() == 'font' || req.resourceType() == 'image')
            {
                req.abort();
            } else
            {
                req.continue();
            }
        });
        await page.goto(url, { timeout: 0 });

        const cursor = createCursor(page);

        await page.waitForXPath(config.selectors.email);
        let el = await page.$x(config.selectors.email);
        await cursor.click(el[0]);
       
        //more irrelevant code
}

thrown errors:

Warning: could not move mouse, error message: Error: Protocol error (Input.dispatchMouseEvent): Target closed (spoof.js: 238)
Warning: could not move mouse, error message: Error: Protocol error (Input.dispatchMouseEvent): Session closed. Most likely the page has been closed (spoof.js: 238)

Warning: could not click mouse, error message: Error: Protocol error (Input.dispatchMouseEvent): Session closed. Most likely the page has been closed. (spoof:320)

The same code works fine with vanilla puppeteer or puppeteer-extra

Puppeteer Types Conflict

Puppeteer started to ship .d.ts files in npm package since February. The DefinitelyTyped package is no longer accurate, I believe. I'm getting the below errors during compilations with "ghost-cursor": "^1.1.5" and "puppeteer": "^10.1.0" installed.

node_modules/ghost-cursor/lib/spoof.d.ts:22:9 - error TS2687: All declarations of '_client' must have identical modifiers.

22         _client: {
           ~~~~~~~

node_modules/ghost-cursor/lib/spoof.d.ts:22:9 - error TS2717: Subsequent property declarations must have the same type.  Property '_client' must be of type 'any', but here has type '{ send: (name: string, params: {}) => Promise<any>; }'.

22         _client: {
           ~~~~~~~

  node_modules/puppeteer/lib/types.d.ts:3855:13
    3855     private _client;
                     ~~~~~~~
    '_client' was also declared here.

node_modules/ghost-cursor/lib/spoof.d.ts:29:15 - error TS2430: Interface 'ElementHandle<ElementType>' incorrectly extends interface 'JSHandle<ElementType>'.

29     interface ElementHandle {
                 ~~~~~~~~~~~~~

node_modules/ghost-cursor/lib/spoof.d.ts:35:9 - error TS2717: Subsequent property declarations must have the same type.  Property 'frame' must be of type '() => Frame | null', but here has type '() => Frame'.      

35         frame: () => Frame;
           ~~~~~

  node_modules/puppeteer/lib/types.d.ts:1803:5
    1803     frame(): Frame | null;
             ~~~~~
    'frame' was also declared here.

node_modules/puppeteer/lib/types.d.ts:1434:22 - error TS2415: Class 'ElementHandle<ElementType>' incorrectly extends base class 'JSHandle<ElementType>'.
  Types of property '_remoteObject' are incompatible.
    Property 'type' is missing in type '{ objectId: string; }' but required in type 'RemoteObject'.

1434 export declare class ElementHandle<ElementType extends Element = Element> extends JSHandle<ElementType> {
                          ~~~~~~~~~~~~~

  node_modules/puppeteer/lib/types.d.ts:7399:13
    7399             type: ('object' | 'function' | 'undefined' | 'string' | 'number' | 'boolean' | 'symbol' | 'bigint');
                     ~~~~
    'type' is declared here.

node_modules/puppeteer/lib/types.d.ts:3855:13 - error TS2687: All declarations of '_client' must have identical modifiers.

3855     private _client;
                 ~~~~~~~


Found 6 errors.

How to use MouseHelper

I see the latest version includes installMouseHelper, is this supposed to work like the video in the README, where you can see a small grey circle where the cursor moves?

If so, could you help explain how to set it up? I am a little new to the node.js game and this was my best guess:

const { installMouseHelper } = require('ghost-cursor');
await installMouseHelper(page)

But I don't see the same grey circle when I use Puppeteer in head-full mode.

Really appreciate the Ghost-cursor team! Ghost-cursor is awesome

Is it possible to add work with an element directly?

/src/spoof.ts

    async click(selector: any) {
      if (selector) {
        await actions.move(selector);
      }
      return page.mouse.down().then(() => page.mouse.up());
    },
    async move(selector: any) {
			const elem = (typeof selector === 'string')
				? await page.$(selector)
				: await selector;
      if (!elem) {```


Example: 
	let cursor = createCursor(page);
	await page.goto(
		'https://infosimples.github.io/detect-headless/', {
		waitUntil: ['domcontentloaded'],
		30000,
	});

	let select = await page.$('#mouse-move-result');
	await cursor.move(select);
	select = await page.$('#plugins-prototype-result');
	await cursor.move(select);
	await cursor.click(select);

What for? There is a case when elements are enumerated, for example, a form with data.
And it’s not always possible to precisely bind to an element selector.

Delay of cusor.click()

Hello !

When I use cursor.click(element) and then make a page.keyboard.type(), there is a delay between the click and the first keystroke. How can I reduce the click delay please ?

Thanks !

Slow down cursor speed

Hello,
Thank you for this great module, very useful !

I think that, in some situations, the cursor is really going too fast. Would it be possible to add a moveDuration option to the click/move functions ?

Thanks !

Overhaul documentation

The README needs some updating to reflect the changes in the code recently:

  • Example of installMouseHelper
  • New function signature for createCursor
  • New function signature for move and click
  • Document moveTo and getRandomPagePoint

Anybody who's willing to check this?

Issue with compiling bezierCurve

I'm getting an issue with running tsc. See below.

node_modules/ghost-cursor/lib/math.d.ts:19:107 - error TS2304: Cannot find name 'Bezier'.

19 export declare const bezierCurve: (start: Vector, finish: Vector, overrideSpread?: number | undefined) => Bezier;

Iframe error

``Error: Protocol error (DOM.scrollIntoViewIfNeeded): Node does not have a layout object
at C:\Users\Drew\WebstormProjects\project\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:208:63
at new Promise ()
at CDPSession.send (C:\Users\Drew\WebstormProjects\project\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:207:16)
at Object. (C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:373:53)
at step (C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:44:23)
at Object.next (C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:25:53)
at C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:19:71
at new Promise ()
at __awaiter (C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:15:12)
at Object.move (C:\Users\Drew\WebstormProjects\project\node_modules\ghost-cursor\lib\spoof.js:332:20)

C:\Users\Drew\WebstormProjects\project>
``

As you can see, the error indicates that something is wrong with the code that attempts to scroll the element into view. Here is the code I used:

``
const page = (await browser.pages())[0];
const cursor = createCursor(page);

await page.goto('file://C:/Users/Drew/WebstormProjects/project/index.html');

await page.waitForSelector("iframe");
const frame = await (await page.$("iframe")).contentFrame();

await frame.waitForSelector(".checkbox");
const checkbox = await frame.$(".checkbox");

console.log("Found checkbox!");
await cursor.click(checkbox);
console.log("Clicked checkbox!");

``

Sometimes Invalid parameters x: double value expected; y: double value

Hey, very randomly i receive this error and unfortunately i don't have a very good way to reproduce it.

Node: v10.16.3
Puppeteer: v2.1.1

I also use Puppeteer Extra Stealth and Ad Blocker plugins, although it does not seem to matter, i don't think :)

(node:991) UnhandledPromiseRejectionWarning: Error: Protocol error (Input.dispatchMouseEvent): Invalid parameters x: double value expected; y: double value expected
    at /xxx/node_modules/puppeteer/lib/Connection.js:183:56
    at new Promise (<anonymous>)
    at CDPSession.send (/xxx/node_modules/puppeteer/lib/Connection.js:182:12)
    at Mouse.move (/xxx/node_modules/puppeteer/lib/Input.js:209:26)
    at Mouse.<anonymous> (/xxx/node_modules/puppeteer/lib/helper.js:112:23)
    at /xxx/node_modules/ghost-cursor/lib/spoof.js:146:43
    at step (/xxx/node_modules/ghost-cursor/lib/spoof.js:44:23)
    at Object.next (/xxx/node_modules/ghost-cursor/lib/spoof.js:25:53)
    at /xxx/node_modules/ghost-cursor/lib/spoof.js:19:71
    at new Promise (<anonymous>)
  -- ASYNC --
    at Mouse.<anonymous> (/xxx/node_modules/puppeteer/lib/helper.js:111:15)
    at /xxx/node_modules/ghost-cursor/lib/spoof.js:146:43
    at step (/xxx/node_modules/ghost-cursor/lib/spoof.js:44:23)
    at Object.next (/xxx/node_modules/ghost-cursor/lib/spoof.js:25:53)
    at /xxx/node_modules/ghost-cursor/lib/spoof.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (/xxx/node_modules/ghost-cursor/lib/spoof.js:15:12)
    at tracePath (/xxx/node_modules/ghost-cursor/lib/spoof.js:134:49)
    at Object.<anonymous> (/xxx/node_modules/ghost-cursor/lib/spoof.js:213:40)
    at step (/xxx/node_modules/ghost-cursor/lib/spoof.js:44:23)
(node:991) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 8)
(node:991) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Snippet of my code:

...

this.page = await this.browser.newPage()

this.cursor = createCursor(this.page)
...

await this.page.waitForSelector('[data-owl-labels]')
await this.cursor.click('[data-owl-labels]')


await this.page.waitForSelector('#searchTerm_Header')
await this.cursor.move('#searchTerm_Header')

Thanks and let me know if there's anything i can do to help on fixing the bug :)

TypeError: elem.remoteObject is not a function

const puppeteer = require('puppeteer');
const {path,createCursor} = require("ghost-cursor");
const url = process.argv[2];

async function run() {
browser = await puppeteer.launch({
args: ['--disable-gpu', '--no-first-run', '--no-sandbox', '--no-zygote'],
"dumpio": true,
"devtools": false,
"ignoreHTTPSErrors": true,
});

const page = await browser.newPage();
const cursor = createCursor(page);
await cursor.move(selector)
await page.goto(url);
await page.screenshot({ path: 'screenshot.png' });
browser.close();

}
run();

Here is Error Message

TypeError: elem.remoteObject is not a function
at Object.<anonymous> (/usr/app/node_modules/ghost-cursor/lib/spoof.js:458:61)
at step (/usr/app/node_modules/ghost-cursor/lib/spoof.js:44:23)
at Object.next (/usr/app/node_modules/ghost-cursor/lib/spoof.js:25:53)
at fulfilled (/usr/app/node_modules/ghost-cursor/lib/spoof.js:16:58)
at processTicksAndRejections (internal/process/task_queues.js:95:5)

xPath not working

await cursor.click("//a[contains(., 'Поиск заказов')]")
i get error
TypeError: elem.boundingBox is not a function at Object.<anonymous> (/home/dmitrykvant/yandexservicebotpuppeteer/node_modules/ghost-cursor/lib/spoof.js:258:50) at step (/home/dmitrykvant/yandexservicebotpuppeteer/node_modules/ghost-cursor/lib/spoof.js:44:23) at Object.next (/home/dmitrykvant/yandexservicebotpuppeteer/node_modules/ghost-cursor/lib/spoof.js:25:53) at fulfilled (/home/dmitrykvant/yandexservicebotpuppeteer/node_modules/ghost-cursor/lib/spoof.js:16:58) at runMicrotasks (<anonymous>)

Ghost-Cursor and Selenium

Hello, it has been some days that I am trying to implement it into selenium. I only need the path generation feature, but for some reason. I cannot manage to move the cursor following it. Is it actually possible? If so, I would really appreciate to know how.

Probably not the best place to ask, but I am kind of desesperate...

How does installMouseHelper work ?

I am using the module, but I don't know how certain functions like installMouseHelper work, what does it do?
What is the difference between move and moveTo?
I tried to leave a donation but I don't see that you have a link :=

puppeteer: how to use with an iframe?

Currently, it's only possible to use it with an element that is on the page but not in an iframe.

When trying to pass the selector of an element in an iframe I get:

Error: Could not find element with selector "#recaptcha-anchor", make sure you're waiting for the elements with "puppeteer.waitForSelector"

Falling back to JS scroll method TypeError: page._client.send is not a function

Running Puppeteer inside a docker container, under Docker I have no problems, but running under Kubernetes I see this debug output. There is no error, just debug output and the script does finish.

Falling back to JS scroll method TypeError: page._client.send is not a function
at Object. (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:426:53)
at step (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:44:23)
at Object.next (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:25:53)
at /home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:19:71
at new Promise ()
at __awaiter (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:15:12)
at Object.move (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:380:20)
at Object. (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:338:48)
at step (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:44:23)
at Object.next (/home/ubuntu/nginx/node_modules/ghost-cursor/lib/spoof.js:25:53)
Quads not found, trying regular boundingBox

------------------- puppeteer script
const { createCursor } = require("ghost-cursor");

    const targetPage = page;
    const cursor = createCursor(targetPage);
    const promises = [];
    promises.push(targetPage.waitForNavigation());
    const element = await waitForSelectors([["aria/Sign in with Azure #new-zocial-azure-oidc > span"]], targetPage, { visible: true });
    await scrollIntoViewIfNeeded(element, timeout);
    await cursor.click(element);
    await Promise.all(promises);

Sometimes misses element

I can't reproduce it, but I have seen this library missing an element. The click apparently hit another element next to it. 99% of the time it seems to work though.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.