OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // A small example application showing the use of the C++ Headless Chrome | |
6 // library. It navigates to a web site given on the command line, waits for it | |
7 // to load and prints out the DOM. | |
8 // | |
9 // Tip: start reading from the main() function below. | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/command_line.h" | |
13 #include "base/memory/weak_ptr.h" | |
14 #include "headless/public/devtools/domains/page.h" | |
15 #include "headless/public/devtools/domains/runtime.h" | |
16 #include "headless/public/headless_browser.h" | |
17 #include "headless/public/headless_devtools_client.h" | |
18 #include "headless/public/headless_devtools_target.h" | |
19 #include "headless/public/headless_web_contents.h" | |
20 #include "ui/gfx/geometry/size.h" | |
21 | |
22 // This class contains the main application logic, i.e., waiting for a page to | |
23 // load and printing its DOM. Note that browser initialization happens outside | |
24 // this class. | |
25 class HeadlessExample : public headless::HeadlessWebContents::Observer, | |
alex clarke (OOO till 29th)
2017/02/10 14:46:47
This should probably extend inspector::Experimenta
Sami
2017/02/10 16:25:26
Hmm, this is supposed to be a really simple exampl
| |
26 public headless::page::Observer { | |
27 public: | |
28 HeadlessExample(headless::HeadlessBrowser* browser, | |
29 headless::HeadlessWebContents* web_contents); | |
30 ~HeadlessExample() override; | |
31 | |
32 // headless::HeadlessWebContents::Observer implementation: | |
33 void DevToolsTargetReady() override; | |
34 | |
35 // headless::page::Observer implementation: | |
36 void OnLoadEventFired( | |
37 const headless::page::LoadEventFiredParams& params) override; | |
38 | |
39 void OnDomFetched(std::unique_ptr<headless::runtime::EvaluateResult> result); | |
40 | |
41 private: | |
42 // The headless browser instance. See main(). | |
43 headless::HeadlessBrowser* browser_; | |
altimin
2017/02/10 14:39:43
UNOWNED?
Sami
2017/02/10 16:25:26
I'm thinking in the age of unique_ptr and friends,
| |
44 // Our tab. | |
45 headless::HeadlessWebContents* web_contents_; | |
altimin
2017/02/10 14:39:43
UNOWNED?
Sami
2017/02/10 16:25:26
Done.
| |
46 // The DevTools client used to control the tab. | |
47 std::unique_ptr<headless::HeadlessDevToolsClient> devtools_client_; | |
48 // A helper for creating weak pointers to this class. | |
49 base::WeakPtrFactory<HeadlessExample> weak_factory_; | |
50 }; | |
51 | |
52 namespace { | |
53 std::unique_ptr<HeadlessExample> g_example; | |
altimin
2017/02/10 14:39:43
I'm slightly terrified about the idea that Headles
Sami
2017/02/10 16:25:26
Good point, let's make this a raw ptr.
| |
54 } | |
55 | |
56 HeadlessExample::HeadlessExample(headless::HeadlessBrowser* browser, | |
57 headless::HeadlessWebContents* web_contents) | |
58 : browser_(browser), | |
59 web_contents_(web_contents), | |
60 devtools_client_(headless::HeadlessDevToolsClient::Create()), | |
61 weak_factory_(this) { | |
62 web_contents_->AddObserver(this); | |
63 } | |
64 | |
65 HeadlessExample::~HeadlessExample() { | |
66 // Note that we shut down the browser last, because it owns objects such as | |
67 // the web contents which can no longer be accessed after the browser is gone. | |
68 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); | |
altimin
2017/02/10 14:39:43
We should also add removing observer from Page dom
Sami
2017/02/10 16:25:26
Oops, done.
| |
69 web_contents_->RemoveObserver(this); | |
70 browser_->Shutdown(); | |
71 } | |
72 | |
73 // This method is called when the tab is ready for DevTools inspection. | |
74 void HeadlessExample::DevToolsTargetReady() { | |
75 // Attach our DevTools client to the tab so that we can send commands to it | |
76 // and observe events. | |
77 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); | |
78 | |
79 // Start observing events from DevTools's page domain. This lets us get | |
80 // notified when the page has finished loading. Note that it is possible | |
81 // the page has already finished loading by now. See | |
82 // HeadlessShell::DevToolTargetReady for how to handle that case correctly. | |
83 devtools_client_->GetPage()->AddObserver(this); | |
84 devtools_client_->GetPage()->Enable(); | |
85 } | |
86 | |
87 void HeadlessExample::OnLoadEventFired( | |
88 const headless::page::LoadEventFiredParams& params) { | |
89 // The page has now finished loading. Let's grab a snapshot of the DOM by | |
90 // evaluating the outerHTML property on the body element. | |
91 devtools_client_->GetRuntime()->Evaluate( | |
92 "document.body.outerHTML", | |
93 base::Bind(&HeadlessExample::OnDomFetched, weak_factory_.GetWeakPtr())); | |
94 } | |
95 | |
96 void HeadlessExample::OnDomFetched( | |
97 std::unique_ptr<headless::runtime::EvaluateResult> result) { | |
98 std::string dom; | |
altimin
2017/02/10 14:39:43
Check that we got a valid result here?
Sami
2017/02/10 16:25:26
Done.
| |
99 if (result->GetResult()->GetValue()->GetAsString(&dom)) | |
100 printf("%s\n", dom.c_str()); | |
101 | |
102 // Shut down the browser (see ~HeadlessExample). | |
103 g_example.reset(); | |
104 } | |
105 | |
106 // This function is called by the headless library after the browser has been | |
107 // initialized. It runs on the UI thread. | |
108 void OnHeadlessBrowserStarted(headless::HeadlessBrowser* browser) { | |
109 // In order to open tabs, we first need a browser context. It corresponds to a | |
110 // user profile and contains things like the user's cookies, local storage, | |
111 // cache, etc. | |
112 headless::HeadlessBrowserContext::Builder context_builder = | |
113 browser->CreateBrowserContextBuilder(); | |
114 | |
115 // Here we can set options for the browser context. As an example we enable | |
116 // incognito mode, which makes sure profile data is not written to disk. | |
117 context_builder.SetIncognitoMode(true); | |
118 | |
119 // Construct the context and set it as the default. The default browser | |
120 // context is used by the Target.createTarget() DevTools command when no other | |
121 // context is given. | |
122 headless::HeadlessBrowserContext* browser_context = context_builder.Build(); | |
123 browser->SetDefaultBrowserContext(browser_context); | |
124 | |
125 // Get the URL from the command line. | |
126 base::CommandLine::StringVector args = | |
127 base::CommandLine::ForCurrentProcess()->GetArgs(); | |
128 if (args.empty()) { | |
129 LOG(ERROR) << "No URL to load"; | |
130 browser->Shutdown(); | |
131 return; | |
132 } | |
133 GURL url(args[0]); | |
134 | |
135 // Open a tab (i.e., HeadlessWebContents) in the newly created browser | |
136 // context. | |
137 headless::HeadlessWebContents::Builder tab_builder( | |
138 browser_context->CreateWebContentsBuilder()); | |
139 | |
140 // We can set options for the opened tab here. In this example we are just | |
141 // setting the initial URL to navigate to. | |
142 tab_builder.SetInitialURL(url); | |
143 | |
144 // Create an instance of the example app, which will wait for the page to load | |
145 // and print its DOM. | |
146 headless::HeadlessWebContents* web_contents = tab_builder.Build(); | |
147 g_example.reset(new HeadlessExample(browser, web_contents)); | |
148 } | |
149 | |
150 int main(int argc, const char** argv) { | |
151 // This function must be the first thing we call to make sure child processes | |
152 // such as the renderer are started properly. The headless library starts | |
153 // child processes by forking and exec'ing the main application. | |
154 headless::RunChildProcessIfNeeded(argc, argv); | |
155 | |
156 // Create a headless browser instance. There can be one of these per process | |
157 // and it can only be initialized once. | |
158 headless::HeadlessBrowser::Options::Builder builder(argc, argv); | |
159 | |
160 // Here you can customize browser options. As an example we set the window | |
161 // size. | |
162 builder.SetWindowSize(gfx::Size(800, 600)); | |
163 | |
164 // Pass control to the headless library. It will bring up the browser and | |
165 // invoke the given callback on the browser UI thread. Note: if you need to | |
166 // pass more parameters to the callback, you can add them to the Bind() call | |
167 // below. | |
168 return headless::HeadlessBrowserMain(builder.Build(), | |
169 base::Bind(&OnHeadlessBrowserStarted)); | |
170 } | |
OLD | NEW |