Giter Site home page Giter Site logo

lucianoganga / simple-headless-chrome Goto Github PK

View Code? Open in Web Editor NEW
217.0 14.0 50.0 3.01 MB

Simple abstraction to use Chrome as a Headless Browser with Node JS

License: MIT License

JavaScript 100.00%
node-browsers unit-testing testing-tools chrome-headless google-chrome chrome horseman

simple-headless-chrome's Introduction

Build Status

simple-headless-chrome

This project is looking for a maintainer

If you'd like to help others in this project, you're more than welcome! I made this project for work and I wanted to make it available for other people, but usually I don't have the time I'd like to have to maintain the project. So, if you're interested, and want to help with this, just let me know :)

It will be mostly having help to answer some doubts and issues.

Thanks!

Important version >= 3.3.0

Version 3.3.0 includes a new feature that allows managing browser tabs.

This new feature comes with some breaking changes that will allow us future scalability.

To avoid problems for people that uses version >= 3.3.0 of this module, we supported those breaking changes with methods that will be deprecated in version 4.0.0.

Introduction

This is an abstraction to use a Headless version of Google Chrome in a very simple way. I was inspired by the next projects:

And I had to read a lot here too:

And you can also use this in heroku thanks to https://github.com/heroku/heroku-buildpack-google-chrome

I built this basically because I got tired of an error I received in an edge case when using PhantomJS (Unhandled reject Error: Failed to load url). So I decided to make my own abstraction, to be used in a heroku app, and simple to use as Horseman.

I didn't have time to document here in the readme, but every method in the source code is documented.

It's really simple to use. I hope I can get some time to make a QuickStart guide + document the API methods here.

You can read my post in Medium about this module: How to tell to a headless Google Chrome to write a post in Medium for you

You can check a video of the module in action clicking in the image below

A quick example

Features

  • Easy to use
  • Multiples Tabs navigation
  • Private tab navigation (incognito mode)
  • Cookies management
  • Full-size screenshots
  • Export to PDF
  • Docker compatible

And comming soon...

  • Video capture (yes, you'll be able to record your navigation and save it as a video or gif)

Collaboration

If you want to collaborate with the project, in any way (documentation, examples, fixes, etc), just send a PR :)

If you rock at making tests, it would be very useful if you can help us making this module better. It's not necesary to build all the tests, but if someone knows how to code the base to add tests to this module, it would really help for someone else to start with this part.

Thank you to everyone who already help submitting a PR! :D

Installation

1) Install Google Chrome Headless

In your PC

Mac: Chrome Headless is shipped in Chrome Canary. You can install it here: https://www.google.com/chrome/browser/canary.html

Linux: Chrome headless is shipped on chrome 59. so you can install Chrome 59 to use the headless mode:

https://askubuntu.com/questions/79280/how-to-install-chrome-browser-properly-via-command-line

sudo apt-get install libxss1 libappindicator1 libindicator7
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome*.deb  # Might show "errors", fixed by next line
sudo apt-get install -f

In a NodeJS Heroku App

Just add the buildpack for Heroku and vualá! Everything is ready You can check the buildpack repository here: https://github.com/heroku/heroku-buildpack-google-chrome

Using a Docker image

With the addition of Chrome Remote Interface into Chrome 59, a simple way to install is using the Docker image for Chrome Headless, such as https://hub.docker.com/r/justinribeiro/chrome-headless/ or https://hub.docker.com/r/yukinying/chrome-headless/

If using Docker, in your app, configure for headless as follows:

const browser = new HeadlessChrome({
  headless: true,
  launchChrome: false,
  chrome: {
    host: 'localhost',
    port: 9222, // Chrome Docker default port
    remote: true,
  },
  browserlog: true
})

2) Install the NPM Module

npm install --save simple-headless-chrome

Compatibility

Thanks to @lewisf, simple-headless-chrome is compatible on NodeJS >= 4! I hope more persons can benefit of this now :)

Usage

const HeadlessChrome = require('simple-headless-chrome')

const browser = new HeadlessChrome({
  headless: true, // If you turn this off, you can actually see the browser navigate with your instructions,
  chrome: {
    userDataDir: '/tmp/headlessDataDir' // This can be null, so a tmp folder will be created and then destroyed
  }
})

Once you have the browser instance, you can call the methods to interact with it.

Methods

inject

Injects JavaScript in the page

Modules available: jQuery, jquery, jQuery.slim and jquery.slim

Parameters

  • moduleOrScript string Javascript code, file, url or name of the module to inject.

Examples

inject('jquery')

You can use jsdelivr to inject any npm or github package in the page
inject('https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js')
inject('https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js')

You can inject a local Javascript file
inject('./custom-file.js')
inject(__dirname + '/path/to/file.js')

Note: the path will be resolved with `require.resolve()` so you can include
files that are in `node_modules` simply by installing them with NPM
inject('jquery/dist/jquery.min')
inject('lodash/dist/lodash.min')

injectRemoteScript

Injects a remote script in the page

Parameters

  • src string Url to remote JavaScript file

Examples

injectRemoteScript(https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js)

injectScript

Injects code in the DOM as script tag

Parameters

  • script string Code to be injected and evaluated in the DOM

evaluate

Evaluates a fn in the context of the browser

Parameters

  • fn {function} - The function to evaluate in the browser
  • args ...any {*} - The arguments to pass to the function

evaluateAsync

Evaluates an async fn in the context of the browser

Parameters

  • fn {function} - The function to evaluate in the browser
  • args ...any {*} - The arguments to pass to the function

evaluateOnNode

Evaluates a fn in the context of a passed node

Parameters

  • node NodeObject The Node Object used to get the context
  • fn {function} - The function to evaluate in the browser
  • args ...any {*} - The arguments to pass to the function

goTo

Navigates to a URL

Parameters

  • url string The URL to navigate to
  • opt (optional, default {})
  • options object The options object. options:

Properties

  • timeout number Time in ms that this method has to wait until the "pageLoaded" event is triggered. If the value is 0 or false, it means that it doesn't have to wait after calling the "Page.navigate" method

getNodeValue

Get the value of an Node.

Parameters

  • node NodeObject The Node Object

Returns object Object containing type and value of the element

getValue

Get the value of an element.

Parameters

  • selector string The target selector
  • frameId string The FrameID where the selector should be searched

Returns object Object containing type and value of the element

setNodeValue

Set the value of an element.

Parameters

  • node NodeObject The Node Object
  • value string The value to set the node to (it may be an array of values when the node is a multiple "HTMLSelectElement")

setValue

Set the value of an element.

Parameters

  • selector string The selector to set the value of.
  • value string? The value to set the selector to
  • frameId string The FrameID where the selector should be searched

fill

Fills a selector of an input or textarea element with the passed value

Parameters

  • selector string The selector
  • value string The value to fill the element matched in the selector
  • frameId string The FrameID where the selector should be searched

clear

Clear an input field.

Parameters

  • selector string The selector to clear.
  • frameId string The FrameID where the selector should be searched

querySelector

Returns the node associated to the passed selector

Parameters

  • selector string The selector to find
  • frameId string The FrameID where the selector should be searched

focus

Focus on an element matching the selector

Parameters

  • selector string The selector to find the element
  • frameId string The FrameID where the selector should be searched

type

Simulate a keypress on a selector

Parameters

  • selector string The selector to type into.
  • text string The text to type.
  • frameId string The FrameID where the selector should be searched
  • opts
  • options object Lets you send keys like control & shift

typeText

Types text (doesn't matter where it is)

Parameters

  • text string The text to type.
  • opts
  • options object Lets you send keys like control & shift

select

Select a value in an html select element.

Parameters

  • selector string The identifier for the select element.
  • value string The value to select.
  • frameId string The FrameID where the selector should be searched

keyboardEvent

Fire a key event.

Parameters

  • type string The type of key event. (optional, default keypress)
  • key string The key to use for the event. (optional, default null)
  • modifier number The keyboard modifier to use. (optional, default 0)
  • windowsVirtualKeyCode (optional, default 0)

wait

Waits certain amount of ms

Parameters

  • time number Ammount of ms to wait

onConsole

Binding callback to handle console messages

Parameters

  • listener is a callback for handling console message

waitForPageToLoad

Waits for a page to finish loading. Throws error after timeout

Parameters

  • timeout number The timeout in ms. (Default: "loadPageTimeout" property in the browser instance options)

waitForFrameToLoad

Waits for all the frames in the page to finish loading. Returns the list of frames after that

Parameters

  • url (regexp | string) The URL that must be waited for load
  • timeout

Returns object List of frames, with childFrames

waitForSelectorToLoad

Waits for a selector to finish loading. Throws error after timeout

Parameters

  • selector string The identifier for the select element.
  • interval number The interval in ms. (Default: "loadPageTimeout" property in the browser instance options)
  • timeout number The timeout in ms. (Default: "loadPageTimeout" property in the browser instance options)

mouseEvent

Fire a mouse event.

Parameters

  • $0 Object
    • $0.type (optional, default 'mousePressed')
    • $0.x (optional, default 0)
    • $0.y (optional, default 0)
    • $0.modifiers (optional, default 0)
    • $0.button (optional, default 'left')
    • $0.clickCount (optional, default 1)
  • type string Type of the mouse event. Allowed values: mousePressed, mouseReleased, mouseMoved. (optional, default mousePressed)
  • x number X coordinate of the event relative to the main frame's viewport. (optional, default 0)
  • y number Y coordinate of the event relative to the main frame's viewport. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport. (optional, default 0)
  • modifier number Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). (optional, default 0)
  • button string Mouse button (default: "none"). Allowed values: none, left, middle, right. (optional, default left)

click

Click on a selector by firing a 'click event' directly in the element of the selector

Parameters

  • selector string Selector of the element to click
  • frameId string The FrameID where the selector should be searched

clickOnSelector

Clicks left button hover the centroid of the element matching the passed selector

Parameters

  • selector string?
  • frameId string The FrameID where the selector should be searched

getNodeCentroid

Calculates the centroid of a node by using the boxModel data of the element

Parameters

Returns object { x, y } object with the coordinates

getCookies

Get the browser cookies

Returns object Object with all the cookies

setCookie

Set the browser cookies

Parameters

  • name string The name of the cookie.
  • value string The value of the cookie.
  • options (optional, default {})
  • url string The request-URI to associate with the setting of the cookie.

Properties

Returns boolean True if successfully set cookie

clearBrowserCookies

Clear the browser cookies

exist

Checks if an element matches the selector

Parameters

  • selector string The selector string
  • frameId string The FrameID where the selector should be searched

Returns boolean Boolean indicating if element of selector exists or not

visible

Checks if an element matching a selector is visible

Parameters

  • selector string The selector string
  • frameId string The FrameID where the selector should be searched

Returns boolean Boolean indicating if element of selector is visible or not

getScreenshot

Takes a screenshot of the page and returns it as a string

Parameters

  • captureOptions object Options object Options properties:
    • captureOptions.format (optional, default 'png')
    • captureOptions.quality
    • captureOptions.clip (optional, default {x:0,y:0,width:this.options.deviceMetrics.width,height:this.options.deviceMetrics.height,scale:this.options.deviceMetrics.deviceScaleFactor})
    • captureOptions.fromSurface
    • captureOptions.selector
    • captureOptions.fullPage
  • returnBinary boolean If true, returns as binary. Otherwise, returns a base64 string (optional, default false)

Properties

  • format string? Image compression format (defaults to png). Allowed values: jpeg, png.
  • quality integer? Compression quality from range [0..100] (jpeg only).
  • clip ViewPort? Capture the screenshot of a given viewport/region only (https://chromedevtools.github.io/devtools-protocol/tot/Page/#type-Viewport)
  • fromSurface boolean? Capture the screenshot from the surface, rather than the view. Defaults to false. EXPERIMENTAL
  • selector string? The selector to be captured. If empty, will capture the page
  • fullPage boolean? If true, captures the full page height

Returns string Binary or Base64 string with the image data

saveScreenshot

Saves a screenshot of the page

Parameters

  • fileName string Path and Name of the file (without the extension) (optional, default `screenshot-${Date.now()}`)
  • captureOptions object Options object Options properties: (optional, default {})
    • captureOptions.format (optional, default 'png')
    • captureOptions.quality
    • captureOptions.clip
    • captureOptions.fromSurface
    • captureOptions.selector
    • captureOptions.fullPage

Properties

  • format string Image compression format (defaults to png). Allowed values: jpeg, png.
  • quality integer Compression quality from range [0..100] (jpeg only).
  • clip ViewPort Capture the screenshot of a given region only (https://chromedevtools.github.io/devtools-protocol/tot/Page/#type-Viewport)
  • fromSurface boolean Capture the screenshot from the surface, rather than the view. Defaults to false. EXPERIMENTAL
  • selector string? The selector to be captured. If empty, will capture the page
  • fullPage boolean? If true, captures the full page height

Returns string Binary or Base64 string with the image data

printToPDF

Prints the page to PDF

Parameters

  • options (optional, default {})
  • returnBinary boolean If true, returns as binary. Otherwise, returns a base64 string (optional, default false)

Properties

  • landscape boolean Paper orientation. Defaults to false.
  • displayHeaderFooter boolean Display header and footer. Defaults to false.
  • printBackground boolean Print background graphics. Defaults to false.
  • scale number Scale of the webpage rendering. Defaults to 1.
  • paperWidth number Paper width in inches. Defaults to 8.5 inches.
  • paperHeight number Paper height in inches. Defaults to 11 inches.
  • marginTop number Top margin in inches. Defaults to 1cm (~0.4 inches).
  • marginBottom number Bottom margin in inches. Defaults to 1cm (~0.4 inches).
  • marginLeft number Left margin in inches. Defaults to 1cm (~0.4 inches).
  • marginRight number Right margin in inches. Defaults to 1cm (~0.4 inches).
  • pageRanges string Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. }} options - Options object

Returns string Binary or Base64 string with the PDF data

savePdf

Saves a PDF file of the page

Parameters

  • fileName string Path and Name of the file (optional, default `pdf-${Date.now()}`)
  • options (optional, default {})

Properties

  • landscape boolean Paper orientation. Defaults to false.
  • displayHeaderFooter boolean Display header and footer. Defaults to false.
  • printBackground boolean Print background graphics. Defaults to false.
  • scale number Scale of the webpage rendering. Defaults to 1.
  • paperWidth number Paper width in inches. Defaults to 8.5 inches.
  • paperHeight number Paper height in inches. Defaults to 11 inches.
  • marginTop number Top margin in inches. Defaults to 1cm (~0.4 inches).
  • marginBottom number Bottom margin in inches. Defaults to 1cm (~0.4 inches).
  • marginLeft number Left margin in inches. Defaults to 1cm (~0.4 inches).
  • marginRight number Right margin in inches. Defaults to 1cm (~0.4 inches).
  • pageRanges string Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. }} options - PDF options

getSelectorViewport

Get the Viewport of the element matching a selector

Parameters

  • selector string The selector string
  • frameId string The FrameID where the selector should be searched

Returns Viewport Object with the viewport properties (https://chromedevtools.github.io/devtools-protocol/tot/Page/#type-Viewport)

getFrames

Get the list of frames in the loaded page

Returns object List of frames, with childFrames

resizeFullScreen

Resize viewports of the page to full screen size

handleDialog

Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload)

Parameters

  • accept boolean Whether to accept or dismiss the dialog (optional, default true)
  • promptText string? The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog. (optional, default '')

post

Post data from the browser context

Parameters

  • url string The URL or path to POST to
  • data object? The data object to be posted (optional, default {})
  • options object? Options of the request (optional, default {})

Returns object Request status and data

value

TODO: Take the value from the DOM Node. For some reason, there're some pages where is not possible to get the textarea value, as its nodeId refreshes all the time

setNodeValue

TODO: Take the value from the DOM Node. For some reason, there're some pages where is not possible to get the textarea value, as its nodeId refreshes all the time

browserIsInitialized

Checks if the browser is initialized. Exits the process if it's not

fixSelector

As the selectors may contain colons, it's necessary to escape them in order to correctly match an element

Parameters

  • selector string The selector string

Returns string The selector with colons escaped (One backslash to escape the ':' for CSS, and other to escape the first one for JS)

promiseTimeout

Runs a promise and throws an error if it's not resolved before the timeout

Parameters

  • promise promise The promise to run
  • timeout number The timeout time, in ms

interleaveArrayToObject

Transforms an interleave array into a key - value object

Parameters

  • interleaveArray array The interleave array

Returns object The key value object

objectToEncodedUri

Given an object, transforms it's properties to a URL encoded string

Parameters

  • object object The object to transform

Returns string The URL Enconded object

sleep

Creates some delay

Parameters

  • delay number Delay in miliseconds

Returns promise The promise that will solve after the delay

Example

const HeadlessChrome = require('simple-headless-chrome')

const browser = new HeadlessChrome({
  headless: true // If you turn this off, you can actually see the browser navigate with your instructions
  // see above if using remote interface
})
async function navigateWebsite() {
  try {
    await browser.init()

    const mainTab = await browser.newTab({ privateTab: false })

    // Navigate to a URL
    await mainTab.goTo('http://www.mywebsite.com/login')

    // Fill an element
    await mainTab.fill('#username', 'myUser')

    // Type in an element
    await mainTab.type('#password', 'Yey!ImAPassword!')

    // Click on a button
    await mainTab.click('#Login')

    // Log some info in your console
    await mainTab.log('Click login')

    // Wait some time! (2s)
    await mainTab.wait(2000)

    // Log some info in your console, ONLY if you started the app in DEBUG mode (DEBUG='HeadlessChrome*' npm start)
    await mainTab.debugLog('Waiting 5 seconds to give some time to all the redirects')

    // Navigate a little...
    await mainTab.goTo('http://www.mywebsite.com/myProfile')

    // Check the select current value
    const myCurrentSubscriptionPlan = await mainTab.getValue('#subscriptionSelect')
    console.log(myCurrentSubscriptionPlan) // {type: 'string', value: '1 month' }

    // Edit the subscription
    await mainTab.select('#subscriptionSelect', '3 months')
    await mainTab.click('#Save')

    // Resize the viewport to full screen size (One use is to take full size screen shots)
    await mainTab.resizeFullScreen()

    // Take a screenshot
    await mainTab.saveScreenshot('./shc.png')

    // Get a HTML tag value based on class id
    const htmlTag = await mainTab.evaluate(function(selector) {
        const selectorHtml = document.querySelector(selector)
        return selectorHtml.innerHTML
    }, '.main'); // returns innerHTML of first matching selector for class "main"

    // Close the browser
    await browser.close()
  } catch (err) {
    console.log('ERROR!', err)
  }
 }
 navigateWebsite()

TODO:

Better docs

Add more methods

  • .waitForSelector
  • .setCookie (set individual cookie) Thanks @saidganim !
  • .setCookies (set a full object of cookies, like the one from .getCookies())

Support more Chrome flags

  • --disable-translate
  • --disable-extensions
  • --no-first-run
  • And many more! Only those useful... All supported thanks to @hugorodrigues. Now just pass an array in the init settings, like this:
const browser = new HeadlessChrome({
    headless: false, // If you turn this off, you can actually see the browser navigate with your instructions
    chrome: {
      flags: [
        '--use-fake-device-for-media-stream',
        '--use-fake-ui-for-media-stream'
      ]
    }
  })

And more...

Tests

I was thinking on using this HTML page to make all the tests: https://github.com/cbracco/html5-test-page

It'd be great to have some unit tests for each HTML element; besides, those test may be useful examples for everyone.

More examples!!!

simple-headless-chrome's People

Contributors

bencevans avatar dcposch avatar gr2m avatar hugorodrigues avatar hugufc avatar iyttor avatar lucianoganga avatar mlessio avatar mtrnord avatar saidganim 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

simple-headless-chrome's Issues

Error: No inspectable targets

I'm facing the issue sometimes on my API using simple-headless-chrome

2017-09-08 04:49:14.021, [log,ERROR,5a9ca759-572b-6484-60b3-9a912ae80a36, 5a9ca759-572b-6484-60b3-9a912ae80a36] message: No inspectable targets, stack: Error: No inspectable targets
    at defaultTarget (/rendering/node_modules/chrome-remote-interface/lib/chrome.js:45:23)
    at /rendering/node_modules/chrome-remote-interface/lib/chrome.js:228:32
    at Promise.linkTransaction (/rendering/node_modules/newrelic/lib/instrumentation/core/globals.js:164:23)
    at Promise.wrapped [as __NR_wrapper] (/rendering/node_modules/newrelic/lib/transaction/tracer/index.js:155:28)
    at wrappedHandler (/rendering/node_modules/newrelic/lib/instrumentation/core/globals.js:198:26)
    at process._tickDomainCallback (internal/process/next_tick.js:135:7)
    at process.wrappedFunction (/rendering/node_modules/newrelic/lib/transaction/tracer/index.js:250:51)

Can someone help to check?

Simulate keyBoardEvent 'End/PageDown' on the loaded Page

I am trying to load a page and go to the End of the page using following code :

    await mainTab.goTo('https://github.com/LucianoGanga/simple-headless-chrome')
    await mainTab.wait(2000)
    await mainTab.keyboardEvent('keyUp', 'End')
    await mainTab.keyboardEvent('keyDown', 'End')

But it is not working . I have seen documentation in the code , Input.dispatchKeyEvent of chrome-devtools. However, none of them is working. Could somebody help ?

no such file or directory, open '/tmp/headlessDataDir/chrome-out.log'

I installed Chrome Canary on my mac but am getting this error when I try: await browser.init();
(node:30851) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: ENOENT: no such file or directory, open '/tmp/headlessDataDir/chrome-out.log'

Testing waitForPageToLoad with SPAs

First let me say that I very much appreciate your work. Am planning to contribute in the future, perhaps this is a good start. I could write a test for waitForPageToLoad with different single page applications that load data from a backend.

Before writing the test I would like to actually understand how I can make this work. So far it seems to work for react+redux, react+mobx, angular1, and angular4. However, it does not seem to work with elm and a CMS called Chrizmas.

I've been trying this out as follows:

const HeadlessChrome = require('simple-headless-chrome');
const fs = require('asfs');

// TODO: move to config
const targets = [
  {name: 'react-redux', url: 'https://react-redux.realworld.io'},
  {name: 'react-mobx', url: 'https://react-mobx.realworld.io/'},
  {name: 'angular-4', url: 'https://angular2.realworld.io/'},
  {name: 'angular-1', url: 'https://angularjs.realworld.io/'},
  {name: 'elm-spa', url: 'http://rtfeldman.github.io/elm-spa-example/'},
  {name: 'chrizmas', url: 'https://crizmas-mvc.realworld.io/'}
];

const browser = new HeadlessChrome({
  headless: true,
  tabs: {
    maxTabs: 1
  }
});

async function getStaticDomHTML(url, screenshotPath) {
  try {
    await browser.init();

    const mainTab = await browser.newTab({ privateTab: true });

    await mainTab.goTo(url, {
      timeout: false,
      bypassCertificate: true
    });
    await mainTab.waitForPageToLoad();

    const html = (await mainTab.evaluate(function() {
      return document.documentElement.innerHTML;
    })).result.value;

    if (screenshotPath) {
      await mainTab.saveScreenshot(screenshotPath);
    }

    await browser.close();

    return html;
  }
  catch (err) {
    await browser.close();
    throw err;
  }
}

(async function() {
  for (let target of targets) {
    try {
        const html = await getStaticDomHTML(target.url, `${__dirname}/../output/${target.name}`);
        await fs.writeFileAsync(`${__dirname}/../output/${target.name}-static.html`, html, 'utf8');
    }
    catch (err) {
      console.error(err);
    }
  }
}());

Results are promising but not perfect.

react-redux:
react-redux

react-mobx:
react-mobx

angular1
angular-1

angular4
angular-4

elm
elm-spa

chrizmas
chrizmas

The URLs come from the realworld project. My plan is to make these work first, then write a test case for it. If you have other SPA example urls, that would be great.

Also, are you ok with tests (integration tests I guess) that depend on these realworld.io projects and backends? They will probably stay alive but this is not guaranteed.

Chrome not closing?

Brilliant package! It simplifies things greatly :)

However after running any script with this package chrome refuses to close. Below is an example script I'm currently working on that produces this issue. Am I doing something wrong?

Chrome Version: 59.0.3071.109

const fs = require('fs')
const HeadlessChrome = require('simple-headless-chrome')

const browser = new HeadlessChrome({
	headless: true
})

async function printToPDF(url, params = {}) {
	await browser.init()
	await browser.goTo(url)

	var pdf = await browser.printToPDF(params)
	fs.writeFile('./output.pdf', pdf, 'base64',()=> {})

	await browser.close()
        // process.exit(0) // closes node process but not chrome
}

printToPDF('http://google.com')

Can't set a specific areas to be screenshotted - still unsuccessful

Hi Luciano,

I have tried several times to screenshotting with clip but still failed.
I dont know how you did it, or what version you have used on those example images.

I tried the latest npm version I also tried 4.3.2 but still failed to screenshot an images based on selector.

cannot find module ./build/Browser.js

cannot find module ./build/Browser.js when im running
node clickSelector.js, its says it cannot find the module ./build/Browser.js

    throw err;
    ^

Error: Cannot find module './build/Browser.js'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/fusionx1/Projects/pantheon/automation/newrelic_capture/simple-headless-chrome/index.js:3:18)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)

How to get values from the iframe ?

How to get whole document body value which is inside iframe But it returns me nothing

const HeadlessChrome = require('simple-headless-chrome');

const browser = new HeadlessChrome({
    headless: false // If you turn this off, you can actually see the browser navigate with your instructions
    // see above if using remote interface
});

async function navigateWebsite() {
    try{
        await browser.init()

        const mainTab = await browser.newTab({ privateTab: false })

        await mainTab.goTo('http://someSiteIframe.com');

        let frames = await mainTab.getFrames()
        await mainTab.wait(2000);

        let sampleId = frames[1].id;

        console.log(sampleId)

        mainTab.getValue('document.body',`${sampleId}`).then(data => {
            console.log(data,sampleId,"From frame")
        });

        const htmlTag = await mainTab.evaluate(function(selector) {
            return document.querySelector(selector)

        }, '.slave-0-1');



        await browser.close()

    }catch (err){
        console.log('ERROR!', err)
    }
}

navigateWebsite()

Error in Babel compiling

I got the issue when running the package with babel

/WORK_SPACE/test/node_modules/simple-headless-chrome/lib/browser.js:22
const { sleep } = require('./util')
          ^

SyntaxError: Unexpected token {
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:387:25)
    at Module._extensions..js (module.js:422:10)
    at Object.require.extensions.(anonymous function) [as .js] (/WORK_SPACE/test/node_modules/babel-register/lib/node.js:152:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at Object.<anonymous> (/WORK_SPACE/test/node_modules/simple-headless-chrome/index.js:1:18)
    at Module._compile (module.js:413:34)
    at Module._extensions..js (module.js:422:10)
    at Object.require.extensions.(anonymous function) [as .js] (/WORK_SPACE/test/node_modules/babel-register/lib/node.js:152:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)

Please give me an advise to fix it.

Unable to take screenshots (as well as other actions) with browser in headless:true

Unable to take screenshots when setting the browser to headless. I noticed that the window's outerHeight is also 0 when headless is turned on (maybe this is intended and I misunderstood) but some expected behavior while developing with headless:false is altered when headless:true. Here is an example:

const HeadlessChrome = require('simple-headless-chrome')
const browser = new HeadlessChrome({
  headless: true 
})

async function test(){

	await browser.init()

	// Open up a new tab
	let mainTab = await browser.newTab();

	// Log what is output in the 'browser' console
	mainTab.onConsole(async function(e){
	  console.log(`Console Says: `, e[0].value)
	})

	//Go to any site
	await mainTab.goTo('https://www.google.com');

	// Resize Screen 
	await mainTab.resizeFullScreen()

	// Log what the window height is in the console
	await mainTab.evaluate(getWindowHeight, null); 
	
	// Take a screenshot
	await mainTab.saveScreenshot('./screenshots/test.png');

	browser.close();
}

function getWindowHeight(){
	console.log("WINDOW ====> " + window.outerHeight);
}
test();

In the console I receive: Console Says: WINDOW ====> 0

In this case, i get a screenshot of nothing.

When I set headless to false, I receive this output in the console:

Console Says: WINDOW ====> 1009

I receive a screenshot of google.com in this case.

Hope the above example helps and let me know if I can provide other insight. Like I mentioned above, taking screenshots is one of the few features that are breaking when headless is turned on (due to the lack of a window maybe? not sure....).

Thanks

M

Simple working example?

const HeadlessChrome = require('simple-headless-chrome')

const browser = new HeadlessChrome({
headless: true // If you turn this off, you can actually see the browser navigate with your instructions,
chrome: {
userDataDir: '/tmp/headlessDataDir' // This can be null, so a tmp folder will be created and then destroyed
}
})

browser.goTo("http://www.google.com");

(node:31486) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: browser.goTo is not a function

Throws error and it is not working as expected or am I missing something?

As per the documentation this module compatible for node>=4., could you please share a simple working example in node 6.x, I mean without using async and await.

This will be very helpful for beginners like me.....

Warning message on goTo function

I use node 7.10.1,

when I use the browser.goTo function in code,
await browser.goTo('https://www.npmjs.com/package/simple-headless-chrome')

I get the following error,
(node:28261) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: browser.goTo is not a function
(node:28261) 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.

Since goTo function throws an error the URL does not open.

Thanks

Usage example on Heroku

Would be great with a documented example of how to get this to work on Heroku.

Using it locally is not a problem, but with the buildpack deploy on Heroku I always get ECONNREFUSED. I assume it has something to do with processes being assigned random port numbers?

{ Error: connect ECONNREFUSED 127.0.0.1:47063
    at Object.exports._errnoException (util.js:1050:11)
    at exports._exceptionWithHostPort (util.js:1073:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1093:14)
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 47063 }```

Windows support?

Are you planning to add Windows support?

From what I understand there is no difference in "how it works" between Linux and Windows versions of Chrome. The only difference is that binary file is named chrome.exe in Windows and google-chrome in Linux. Am I right?

browser.click doesn't handle long selectors

  1. Im getting an error if I put a string like this as my selector:
    await browser.click('a[href="/accounts/1388696/applications/20920975"]')
    I get this:
    (node:13030) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Can not query selector a[href='/accounts/'1388696/applications/20920975'] in frame "root": Error: DOM Error while querying

  2. Im getting an error if I put a string like this as my selector:
    await browser.click('div ul:nth-child(3) li.app-box.editable div.single-portal-app')
    I get this:
    (node:76434) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Can not query selector div ul:nth-child(3) li.app-box.editable div.single-portal-app in frame "root": Error: DOM Error while querying
    (node:76434) 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.

Function "visible" missing await

When I try to call visible, I get the following error:

"TypeError: Cannot read property 'value' of undefined"

Looking at the source, every other call to this.evaluate() uses await, but visible handles it synchronously.

When I moved visible.result.value to a .then() handler, it worked fine.

handle file uploads

while trying to find a way to upload files I've found cyrus-and/chrome-remote-interface#164 which uses DOM.setFileInputFiles api call.
now wonder what is the minimum amount of work required to enable this feature - i.e. expose some generic way to call the DOM api?

waitForFrameToLoad not working as expected

I am trying to inject an iframe into a new tab and need to wait for it to finish loading before proceeding. In the example below I am trying to use waitForFrameToLoad:

const baseURL = "about:blank";
// Open up a new tab
  let mainTab = await browser.newTab();

  //inject iframe into this tab - (iframetester creates an Iframe and injects it into the DOM
  const iframe = await mainTab.evaluate(iframeTester, "http://www.exampleURL.com"); 

  await mainTab.waitForFrameToLoad(baseURL, 5000); // Should be waiting for iframe to load for this
  

The goal is to inject an iframe and wait until it has fully loaded to take next actions. The mainTab.waitForFrameToLoad doesn't throw an error, but doesn't seem to be waiting - ideally I would want to be listening for any changes in the DOM (as well as if the src inside the iframe busts out/etc...)- Is there support for page listeners such as Page.loadEventFired as well as the other Page domain listeners? How would I be able to implement these listeners using your library?

Thanks so much.

M

chrome-launcher not stating

/home/developer/node_modules/chrome-launcher/chrome-launcher.js:31
function launch(opts = {}) {
^

SyntaxError: Unexpected token =
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:374:25)
at Object.Module._extensions..js (module.js:417:10)
at Module.load (module.js:344:32)
at Function.Module._load (module.js:301:12)
at Module.require (module.js:354:17)
at require (internal/module.js:12:17)
at Object. (/home/developer/node_modules/chrome-launcher/index.js:6:10)
at Module._compile (module.js:410:26)
at Object.Module._extensions..js (module.js:417:10)

setCookie documentation is wrong

setCookie documentation in README.md says:

Parameters

  • name string The name of the cookie.
  • value string The value of the cookie.
  • options (optional, default {})
  • url string The request-URI to associate with the setting of the cookie.

So this should work:
await mainTab.setCookie("cookie", "1", {}, "http://example.com")

It does not. Right syntax seems to be:
await mainTab.setCookie("cookie", "1", {url: "http://example.com"})

browserIsInitialized is not a function

Hello again!

I am trying to call browserIsInitialized on a tab (as its listed in the readMe) or on the browser and both return an error:

mainTab.browserIsInitialized is not a function or browser.browserIsInitialized is not a function.

Here is the example I used:

	await browser.init()

	// Open up a new tab
	let mainTab = await browser.newTab();
        // This will return an error
	let browserAlive = await mainTab.browserIsInitialized()

	console.log('Browser Alive?', browserAlive);

I looked at your Browser class and it seems like isInitialized method returns !!this.client.

I tested that in this example - and that works fine:

	await browser.init()

	// Open up a new tab
	let mainTab = await browser.newTab();

	let browserAliveNow = await browser.isInitialized()
	console.log('Browser Alive?', browserAliveNow); //true


	console.log(!!mainTab.client);  // true
	console.log(!!browser.client);  // true

	await	browser.close();
	console.log('-- AFTER BROWSER CLOSED --')
	console.log(!!mainTab.client);  // true
	console.log(!!browser.client);  // false


	let browserAlive = await browser.isInitialized()
	console.log('Browser Alive?', browserAlive); //false

The way your documentation is structured - it appears the browserIsInitialized is a method on a new tab (like evaluate, goTo, etc...). Maybe this needs to be listed as a method on the browser instead?

I can make a PR if you would like.

Thanks Lucho,
M

Cannot get onConsole working

Howdy! I like you library.

I cannot seem to capture console messages from my web page. My web page has several console messages that I need to trap in order to trigger a screen capture. Everything else seems to be working great. If you could give me an example of "onConsole", that would propel me forward. Thanks!

Puppeteer?

Just curious, was this library initiated before or after puppeteer?

Do you see the two libraries living alongside each other or do they serve the same purpose?

Sample example not working

I have node version 4.2.x and I have installed the npm.

I'm trying out the sample example given below,
I have saved the file as index.js
const HeadlessChrome = require('simple-headless-chrome') const browser = new HeadlessChrome({ headless: true, launchChrome: true , chrome: { host: 'localhost', port: 9222, // Chrome Docker default port remote: true, }, browserlog: true }); this.browser = browser.init().then(function (data) { return browser; }, function (err) { console.log(err) }) console.log(this.browser.goTo);

I execute as node index.js
and I get the following error,
function launch(opts = {}) {
^

SyntaxError: Unexpected token =
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:414:25)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:313:12)
at Module.require (module.js:366:17)
at require (module.js:385:17)
at Object. (/home/guidanz-kavi/Documents/nodeApplication/skedler/node_modules/chrome-launcher/index.js:6:10)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)

Please guide me resolve this error.
Thanks.

access to chrome and cdp object

Hi, could you please, make chrome and cdp object as public properties? I might do some feature that this lib does not support out of the box.

I need to read all requests after chrome loading an url (like what we see in F12/Network tab of chrome-with-head). Or are there any way to have that information?

Thank you.

Make `simple-headless-chrome` run in node LTS

hey @LucianoGanga I wonder if you would be okay to change the code of the lib/* files so that the library would run in older node versions? We can still use async/await in tests. And I don’t think that the code become less readable.

We have a project where we would love to use simple-headless-chrome but can’t right now because we can’t upgrade the node versions anytime soon :( I’d be happy to send a PR myself. If you are unsure, I can start so you can see some of the diff. Let me know :)

getFrames returns a promise

I'm trying to interact with getFrames but it doesn't return an object as the docs say, it actually returns a promise. I tried interfacing with the promise with no luck. How are you supposed to interact with it?

const HeadlessChrome = require('simple-headless-chrome')

const browser = new HeadlessChrome({headless: true})

async function navigateWebsite() {
  await browser.init();
  const mainTab = await browser.newTab({ privateTab: false });
  await mainTab.goTo('http://www.rollingstone.com')
  await mainTab.wait(10000);
  const frames = mainTab.getFrames();
  console.log(frames);
  await browser.close();
 }
 navigateWebsite();
Promise {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined }

getCookies()

Does the getCookies() function show all Cookies loaded by Chrome? HTTP & JavaScript, main frame and iframes, 1st party and 3rd party?

I'm seeing far fewer Cookies than when using the actual Chrome browser.

If you visit any large e-commerce store or major website, it'll drop 100+ cookies, many from 3rd party domains for ad retargeting etc. Yet getCookies() returns no more than 30 cookies. I've even set wait() to 60 seconds and still don't get the full picture.

const HeadlessChrome = require('simple-headless-chrome')
const browser = new HeadlessChrome({
  headless: true
})
async function navigateWebsite () {
  try {
    await browser.init()
    const mainTab = await browser.newTab({ privateTab: false })
    await mainTab.goTo('http://www.marksandspencer.com/')
    await mainTab.wait(60000)
    await console.log( await mainTab.getCookies() )
    await browser.close()
  } catch (err) {
    console.log('ERROR!', err)
  }
}
navigateWebsite()

The code above gives me 24 cookies from .marksandspencer.com, .gwallet.com, .bluekai.com, .impdesk.com and .demdex.net.

But using regular Chrome gives me 127 cookies from .addthis.com, .adnxs.com, .adsrvr.org, .bidswitch.net, .bluekai.com, .cw.addthis.com, .demdex.net, .doubleclick.net, .dpm.demdex.net, .edrcdn.com, .edrcode.com, .facebook.com, .flashtalking.com, .google.co.uk, .google.com, .gwallet.com, .impdesk.com, .marksandspencer.com, .pixel.rubiconproject.com, .po.st, .rlcdn.com, .rubiconproject.com, .scorecardresearch.com, .univide.com, dpm.demdex.net, pixel.rubiconproject.com, www.google.co.uk and www.google.com.

Am I missing something?

getValue returns undefined

Hm. Not sure if this is my error or a bug.

Using getValue returns undefined for a valid element.

  // <div class="graph-metric-current">Test</div>
    var alpha = await browser.getValue('.graph-metric-current')
    console.log(alpha)

The returned should be a HTML value of the .graph-metric-current node shouldn't it? Using util.inspect also returns undefined, so I'm not quite sure what the object is meant to be.

Cheers

Script not terminating after execution.

Scripts are waiting some time before exiting after the execution.
The script is waiting for the timeout to resolve, after the default sleep timeout (60000ms), then it returns to the console.

It seems a problem related to the setTimeout in the promiseTimeout method.

Just opened a PR that fixes this issue here: #19

FrameID selection broken for framesets?

If I have a document that contains a frameset:

<frameset cols="*">
  <frame id="the_frame" name="the_frame" src="frame.html">
</frameset>

And that frame file contains a button:

<button id='the_button'>Click me</button>

I expect the following code to work:

async function navigateWebsite() {
        await browser.init();
        const mainTab = await browser.newTab( { privateTab: false } );
        await mainTab.goTo( '...' ); // URL of page containing iframe
        await mainTab.wait( 1000 );
        let frames = await mainTab.getFrames();
        frames = frames.filter( f => f.name === 'the_frame' );
        const frame = frames[0].id;
        await mainTab.click( '#the_button', frame );
} );

Instead I receive this error:

(node:18709) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: No node with given id found
(node:18709) [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.

What is the the correct value to pass as frameId? Is this a bug or am I just misunderstanding usage?

Error using sample code in readme

Any ideas?

await browser.init()
^^^^^^^
SyntaxError: Unexpected identifier
at Object.exports.runInThisContext (vm.js:76:16)
at Module._compile (module.js:542:28)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3

Cannot start ChromeHeadless

I have installed chrome headless globally on jenkins machine. Im using karma. I have set variable CHROME_BIN to '/var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs_latest_globals/bin/chrome-headless'. Im getting 'Cannot start ChromeHeadless' error from jenkins when karma tries to run tests via chrome headless. Can somebody help?

error on resizeFullScreen and saveScreenshot(fullPage: true)

When using resizeFullScreen() or saveScreenshot() with fullPage: true the following error is thrown:

ERROR! { Error: Invalid parameters (fitWindow: boolean value expected)
    at /node_modules/chrome-remote-interface/lib/chrome.js:90:30
    at Chrome.handleMessage (/node_modules/chrome-remote-interface/lib/chrome.js:289:13)
    at WebSocket.<anonymous> (/node_modules/chrome-remote-interface/lib/chrome.js:266:27)
    at emitTwo (events.js:125:13)
    at WebSocket.emit (events.js:213:7)
    at Receiver._receiver.onmessage (/node_modules/ws/lib/WebSocket.js:143:54)
    at Receiver.dataMessage (/node_modules/ws/lib/Receiver.js:385:14)
    at extension.decompress (//node_modules/ws/lib/Receiver.js:354:40)
    at _inflate.flush (/node_modules/ws/lib/PerMessageDeflate.js:279:12)
    at afterWrite (_stream_writable.js:452:3)
    at onwrite (_stream_writable.js:443:7)
    at InflateRaw.afterTransform (_stream_transform.js:90:3)
    at Zlib.callback (zlib.js:514:5)
  response: 
   { code: -32602,
     message: 'Invalid parameters',
     data: 'fitWindow: boolean value expected' } }

saveScreenshot clip param doesn't work

When I clip a region screenshot user api saveScreenshot, but the result also get full screenshot.

await mainTab.goTo(url)

// Resize the viewport to full screen size (One use is to take full size screen shots)
await mainTab.resizeFullScreen()

// Wait some time! (2s)
await mainTab.wait(2000)

const regionClip = {
      x: 0,
      y: 0,
      width: 500,
      height: 500,
      scale: 1
};
    await mainTab.saveScreenshot('/test', {clip:regionClip })

Cannot read property 'kill' of undefined

Hi all,

I got the issue when running with docker configuration

Cannot read property 'kill' of undefined, stack: TypeError: Cannot read property 'kill' of undefined
    at Browser._callee$ (/WORK_SPACE/src/.../node_modules/simple-headless-chrome/build/Browser.js:129:43)

The config I did

chromeConfig = {
        headless: true,
        launchChrome: false,
        chrome: {
            host: remoteChromeConfig.host,
            port: remoteChromeConfig.port,
            remote: true
        },
        browserlog: true
};

I'm seeing the document is out of date with the latest version. It might be a wrong configuration. Any advises to resolve the issue?

I have just checked the source code, there is no kill function in chrome.js file. The source code has issues?

How to click on elements if there is no class or id

Hi ,

I am exploring this module , and I want to move my code from node horseman to this library. But I have few elements which neither have an id no a class , is it possible to do something like this
.click('a[href="xyz.aspx"]')

e.g. element : xyzzy

Thanks

PDF is not generating?(printToPDF fn)

const HeadlessChrome = require('../index')
const browser = new HeadlessChrome({
headless: true
})
async function navigateWebsite() {
try {
await browser.init()

    // Open a new Tab
    const mainTab = await browser.newTab({ privateTab: true })

    // Navigate to a URL
    await mainTab.goTo('https://github.com/cognitom/paper-css/issues/13')

    await mainTab.wait(10000)

await mainTab.printToPDF('/home/iyappan/Documents/iyy/software/node_modules/simple-headless-chrome/examples/simple-headless-chrome-files3')
  // Close the browser
    await browser.close()
} catch (err) {
    console.log('ERROR!', err)
}

}
navigateWebsite()

This is my code.I've referred the documents,When i use the printToPDF function,not getting the PDF output.Can you provide the solutions of it?

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.