(转载)利用webkit抓取动态网页和链接

简介:

做爬虫的时候最头疼的就是遇到一些动态加载的页面或者是一些动态生成的链接。

比如我们的博客园就是个例子:

 

凤凰网的评论链接也是一样:

今天我们就用Webkit来解决这个问题。

 

预备知识可以看一下我前面几篇文章,准备工作参照利用InjectedBundle定制自己的Webkit(二)中的客户端程序。

一切就绪之后我们开始!

 

首先介绍一些重要的函数和回调

在创建一个Page之后我们可以设置一些回调函数,其中有一个是:

WKPageLoaderClient::didFinishDocumentLoadForFrame

原型是:

typedef void (*WKPageDidFinishLoadForFrameCallback)(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo);

这个函数是在一个Frame加载完毕之后调用。由于每个Page都有一个 mainFrame,而mianFrame又可能拥有若干个childFrame,只有在所有childFrame加载完毕之后mainFrame才算加 载完毕,所以我们可以认为当mainFrame回调didFinishDocumentLoadForFrame的时候就是整个Page加载完毕的时候。 换句话说这个时候所有的动态内容也都加载完毕了。我们可以在这个回调中获取我们需要的页面内容。

一个简单的例子:

WKContextRef context = WKContextGetSharedProcessContext();
RECT webViewRect = { 0, 0, 0, 0};
WKViewRef view = WKViewCreate(webViewRect, context, 0, m_window);
WKPageLoaderClient loaderClient = { 0 };
loaderClient.version = kWKPageLoaderClientCurrentVersion;
loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
WKPageSetPageLoaderClient(WKViewGetPage(view), &loaderClient);

大家都知道JavaScript功能强大,而Webkit给我们提供了运行自己的JS的接口,所以要提取我们想要的内容并非难事。调用方法如下:

WKStringRef script = WKStringCreateWithUTF8CString("1.1 + 1.5");
WKPageRunJavaScriptInMainFrame(page, script, 0, scriptResultCallback);

这是一个简单的例子运行1.1 + 1.5简单的浮点计算,这里面用到的page就是回调得到的WKPageRef,scriptResultCallback是执行完毕之后的回调。接下来编写回调函数处理执行结果:

void scriptResultCallback(WKSerializedScriptValueRef value, WKErrorRef, void* context)
{
JSGlobalContextRef scriptContext = JSGlobalContextCreate(0);
JSValueRef exc;
JSValueRef var = WKSerializedScriptValueDeserialize(value, scriptContext, &exc);
double dd = JSValueToNumber(scriptContext, var, &exc);
wchar_t info[1024];
swprintf(info, L"result is: %f", dd);
::MessageBox(NULL, info, L"Script", MB_OK);
JSGlobalContextRelease(scriptContext);
}

运行结果如下:

 

既然能够得到正确的结果那我们开始解决第一个问题:提取动态内容

下面的例子是用JS把页面body部分的代码提取出来

var wholeHtmlString = '';    // 存放HTML

function myPrintTag(node)
{
if (node.nodeName == '#text')  // 文本块直接打印内容
{
wholeHtmlString += node.textContent;
wholeHtmlString += '\n';
return 'text';
}
else if (node.nodeName == '#comment')  // 过滤注释
{
return 'comment';
}
else if (node.nodeName == 'SCRIPT')  // 过滤JS
{
return 'script';
}

wholeHtmlString += '<';
wholeHtmlString += node.nodeName;
wholeHtmlString += ' ';
if (node.hasAttributes())
{
for (var i = 0; i < node.attributes.length; i++)  // 输出节点属性
{
var attr = node.attributes.item(i);
wholeHtmlString += attr.name;
wholeHtmlString += '=\'';
wholeHtmlString += attr.value;
wholeHtmlString += '\' ';
}
}
wholeHtmlString += '>\n';
return 'normal';
}

function myProcessNode(parent)
{
var nodeType = myPrintTag(parent);  // 输出当前节点
if (nodeType == 'normal')
{
if (parent.hasChildNodes())
{
for (var i = 0; i < parent.childNodes.length; i++)  // 输出孩子节点
{
myProcessNode(parent.childNodes.item(i));
}
}
wholeHtmlString += '</';
wholeHtmlString += parent.nodeName;
wholeHtmlString += '>\n';
}
}

function myPrintHtml()
{
myProcessNode(document.body);  // 输出body部分
return wholeHtmlString;
}

myPrintHtml();

要注意的地方是注释和文本节点转成HTML的时候需要特殊处理,利用这种方式可以轻松地自定义需要得到的部分。

 

接下来解决第二个问题:提取动态链接

我们浏览网页的时候要跳转到一个新的链接通常都是用鼠标点击一下即可,我们就可以模拟这一过程来提取出动态生成的链接。先看JS代码:

var clickEvt = document.createEvent('Event');
clickEvt.initEvent('click', true, true);
myObject.dispatchEvent(clickEvt);

myObject是我们想要获取链接的DOM节点,利用给目标DOM节点发送一个click消息就能够模拟鼠标点击事件,然后要做的就是捕获跳转的请求。

在页面将要导航到新的URL的时候,会调用一个回调:

WKPagePolicyClient::decidePolicyForNavigationAction

在将要创建一个新的页面的时候,会调用一个回调:

WKPagePolicyClient::decidePolicyForNewWindowAction

利用这两个回调,就能捕获到上文提到的跳转请求。下面看一个例子:

首先注册一下回调函数

WKPagePolicyClient policyClient = { 0 };
policyClient.version = kWKPagePolicyClientCurrentVersion;
policyClient.decidePolicyForNavigationAction = decidePolicyForNavigationAction; 
policyClient.decidePolicyForNewWindowAction = decidePolicyForNewWindowAction;
WKPageSetPagePolicyClient(page), &policyClient);

然后编写回调函数

void decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, 
WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, 
WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, 
  const void* clientInfo)
{
didRecvNewNavigation(frame, request, listener);
}

void decidePolicyForNewWindowAction(WKPageRef page, WKFrameRef frame, 
WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, 
WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, 
  const void* clientInfo)
{
didRecvNewNavigation(frame, request, listener);
}

之后我们在didRecvNewNavigation中统一处理

void didRecvNewNavigation(WKFrameRef frame, WKURLRequestRef request, WKFramePolicyListenerRef listener)
{
if (页面加载完毕)
{
WKURLRef url = WKURLRequestCopyURL(request);
// 处理获得的url
WKFramePolicyListenerIgnore(listener);  // 不加载该url
}
else
{
if (WKFrameIsMainFrame(frame))  // 如果是主frame
{
WKFramePolicyListenerUse(listener);  // 加载url
}
else
{
WKFramePolicyListenerIgnore(listener);  // 不加载该url
}
}
}

判断页面加载完成的时机之前已经说了,只要用一个状态变量记录即可。这里主要讲一 下WKFramePolicyListenerRef,这个可以设置Webkit是否加载指定的URL,也就是可以过滤掉不需要的加载,提高效率。因为一 般我们需要的内容都处于mainFrame中,所以这里只加载了mainFrame的内容。

至此我们就完成了动态内容和链接的提取,通过适当的改造就可以变成自己定义的多功能爬虫了。

来源:http://www.cnblogs.com/Jiajun/archive/2012/12/12/2813888.html




本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2013/03/04/2943374.html,如需转载请自行联系原作者

目录
相关文章
|
1月前
|
Web App开发
在 HTML 中禁用 Chrome 浏览器的 Google 翻译功能
在 html 标签中添加 translate=“no” 属性,浏览器将不会翻译整个页面。
38 0
|
3月前
|
数据采集 Web App开发 JSON
浏览器插件:WebScraper基本用法和抓取页面内容(不会编程也能爬取数据)
本文以百度为实战案例演示使用WebScraper插件抓取页面内容保存到文件中。以及WebScraper用法【2月更文挑战第1天】
152 2
浏览器插件:WebScraper基本用法和抓取页面内容(不会编程也能爬取数据)
|
5月前
|
数据采集 Java 数据挖掘
如何使用ScrapySharp下载网页内容
如何使用ScrapySharp下载网页内容
|
12月前
vba 在网页中抓取指定内容
vba 在网页中抓取指定内容
57 0
|
存储 Web App开发 数据采集
30分钟开发一款抓取网站图片资源的浏览器插件
由于业务需求, 笔者要为公司开发几款实用的浏览器插件,所以大致花了一天的时间,看完了谷歌浏览器插件开发文档,在这里特地总结一下经验, 并通过一个实际案例来复盘插件开发的流程和注意事项.
336 0
|
数据采集 Web App开发 监控
10分钟教你Python爬虫(上)-- HTML和爬虫基础
10分钟教你Python爬虫(上)-- HTML和爬虫基础
334 0
10分钟教你Python爬虫(上)-- HTML和爬虫基础
|
算法 前端开发 JavaScript
浅谈Google蜘蛛抓取的工作原理(02)
浅谈Google蜘蛛抓取的工作原理
327 0
浅谈Google蜘蛛抓取的工作原理(02)
|
存储 JavaScript 前端开发
浅谈Google蜘蛛抓取的工作原理(01)
浅谈Google蜘蛛抓取的工作原理
430 0
浅谈Google蜘蛛抓取的工作原理(01)
|
Web App开发 监控 Linux
Web网站如何查看搜索引擎蜘蛛爬虫的行为
简介 本文给大家介绍Linux/Nginx如何查看搜索引擎蜘蛛爬虫的行为,清楚蜘蛛的爬行情况对做SEO优化有很大的帮助。需要的朋友通过本篇文章学习下吧 摘要 做好网站SEO优化的第一步就是首先让蜘蛛爬虫经常来你的网站进行光顾,下面的Linux命令可以让你清楚的知道蜘蛛的爬行情况。
2772 0