关于 TFHpple 框架的使用求助

2015-11-19 13:40:56 +08:00
 UtopiaCHN

我想解析下面这段 HTML 代码,这段代码属于 https://www.v2ex.com/?tab=tech 页面的代码。

<div class="cell item" style=""><div style="position: absolute; margin: -10px -10px 0px 650px;"></div>
    <table cellpadding="0" cellspacing="0" border="0" width="100%">
        <tr>     
           <td width="48" valign="top" align="center"><a href="/member/xiaobaike"><img src="//cdn.v2ex.co/gravatar/1d27a1b82bcc599bfd0ffad63f3a588b?s=48&d=retro" class="avatar" border="0" align="default" style="max-width: 48px; max-height: 48px;" /></a></td>
            <td width="10"></td>

            <td width="auto" valign="middle"><span class="item_title"><a href="/t/237254#reply3">新版 google+自扇狗脸</a></span>
            <div class="sep5"></div>
            <span class="small fade"><div class="votes"></div><a class="node" href="/go/android">Android</a> &nbsp;•&nbsp; <strong><a href="/member/xiaobaike">xiaobaike</a></strong> &nbsp;•&nbsp; 23 分钟前 &nbsp;•&nbsp; 最后回复来自 <strong><a href="/member/864766428">864766428</a></strong></span>
            </td>
            <td width="70" align="right" valign="middle">

                <a href="/t/237254#reply3" class="count_livid">3</a>

            </td>
        </tr>
     </table>
 </div>

我用下面的代码获取了上面 html 代码的内容.

NSArray * elements  = [doc searchWithXPathQuery:@"//div[@class='cell item']"];

    TFHppleElement * element = [elements objectAtIndex:0];

接下来应该怎么获取<a href="/member/xiaobaike"><img src="//cdn.v2ex.co/gravatar/1d27a1b82bcc599bfd0ffad63f3a588b?s=48&d=retro" class="avatar" border="0" align="default" style="max-width: 48px; max-height: 48px;" /></a><a href="/t/237254#reply3">新版 google+自扇狗脸</a> 里面的图片和文字。

3264 次点击
所在节点    iDev
20 条回复
black
2015-11-19 15:13:54 +08:00
[element firstChildWithClassName:@"avatar"];

[[element firstChildWithClassName:@"item_title"] firstChildWithTagName:@"a"];
UtopiaCHN
2015-11-19 15:58:07 +08:00
@black 打印出来是空的( null )。。这是我实现的代码
```
NSURL *URL = [NSURL URLWithString:@"https://www.v2ex.com/?tab=tech"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];

[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

NSData * data = responseObject;
TFHpple * doc = [[TFHpple alloc] initWithHTMLData:data];

NSArray * elements = [doc searchWithXPathQuery:@"//div[@class='cell item']"];
TFHppleElement * element = [elements objectAtIndex:0];

NSLog(@"%@", [element firstChildWithClassName:@"avatar"]);
NSLog(@"%@", [[element firstChildWithClassName:@"item_title"] firstChildWithTagName:@"a"]);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];

[op start];

```
black
2015-11-19 16:37:13 +08:00
不好意思,上面的代码是错误的。

方案一:

首先给 TFHppleElement 增加两个方法:

- (TFHppleElement *)findFirstSubnodeWithClassName:(NSString *)className
{
for (TFHppleElement *child in self.children) {
if ([[child objectForKey:@"class"] isEqualToString:className]) {
return child;
}

TFHppleElement *find = [child findFirstSubnodeWithClassName:className];
if (find) {
return find;
}
}
return nil;
}

- (TFHppleElement *)findFirstSubnodeWithTagName:(NSString *)tagName
{
for (TFHppleElement *child in self.children) {
if ([[child tagName] isEqualToString:tagName]) {
return child;
}

TFHppleElement *find = [child findFirstSubnodeWithTagName:tagName];
if (find) {
return find;
}
}
return nil;
}

然后代码改一下:

[element findFirstSubnodeWithClassName:@"avatar"];

[[element findFirstSubnodeWithClassName:@"item_title"] findFirstSubnodeWithTagName:@"a"];


方案二:

根据得到的 TFHppleElement 实例再创建一个 TFHpple 对象:

NSData *elementData = [[element raw] dataUsingEncoding:NSUTF8StringEncoding];
TFHpple *elementHpple = [[TFHpple alloc] initWithHTMLData:elementData];

然后再次使用 XPath 查询 avatar:

TFHppleElement *avatarElement = [[elementHpple searchWithXPathQuery:@"//img[@class=\"avatar\""] firstObject];
xuyinan503
2015-11-19 16:56:09 +08:00
UtopiaCHN
2015-11-19 22:28:03 +08:00
@black 太感谢了,这个问题我折腾了好久,终于解决了。不过方案二报错了,错误信息是:
XPath error : Invalid predicate
XPath error : Invalid expression
2015-11-19 22:27:05.463 V2EX[14762:580730] Unable to evaluate XPath.
2015-11-19 22:27:05.464 V2EX[14762:580730] (null)
UtopiaCHN
2015-11-19 22:28:58 +08:00
@xuyinan503 里面没有分类页面的 api ,只能解析 html 。。。
black
2015-11-20 10:14:38 +08:00
XPath 写错了,改一下就好:

TFHppleElement *avatarElement = [[elementHpple searchWithXPathQuery:@"//img[@class=\"avatar\"]"] firstObject];
UtopiaCHN
2015-11-22 05:50:29 +08:00
@black 真的很感谢。
UtopiaCHN
2015-11-22 06:37:39 +08:00
@black 能不能再请教一个问题,我想拿到下面代码中的“ 2 小时 0 分钟前”,我用<span>节点的 content ( element.content )输出得到的是: Python  •  meloncrashed  •  2 小时 0 分钟前。如果我想拿到“ 2 小时 0 分钟前”是不是只能从字符串层面进行处理呢?


<span class="small fade">
<div class="votes"></div>
<a class="node" href="/go/python">Python</a> &nbsp;•&nbsp;
<strong><a href="/member/meloncrashed">meloncrashed</a></strong> &nbsp;•&nbsp;
2 小时 0 分钟前
</span>
black
2015-11-22 07:58:32 +08:00
试试 element.text
UtopiaCHN
2015-11-22 19:47:12 +08:00
@black 这样输出的是:  •  ,好奇怪。
black
2015-11-23 18:42:06 +08:00
文本在 hpple 里抽象成 textNode, 遍历当前元素,找到所有的 textNode, 再去 textNode 集合里拿你想要的: &nbsp;•&nbsp; 2 小时 0 分钟前
black
2015-11-23 18:43:42 +08:00
for (TFHppleElement *child in self.children) {
if ([child isTextNode]) {
// ...
}
UtopiaCHN
2015-11-23 22:56:43 +08:00
@black 输出来是空的。。

这是我的代码:
NSArray *elements = [element searchWithXPathQuery:@"//span[@class='small fade']"];

e = [elements objectAtIndex:0];

for (TFHppleElement *child in e.children)
{
if ([child isTextNode])
{
NSLog(@"%@", child.text);
}
}

处理的 html :
<span class="small fade">
<div class="votes"></div>
<a class="node" href="/go/python">Python</a> &nbsp;•&nbsp;
<strong><a href="/member/meloncrashed">meloncrashed</a></strong> &nbsp;•&nbsp;
2 小时 0 分钟前
</span>
black
2015-11-23 23:11:04 +08:00
建议楼主先研究一下源代码,分清楚 text 和 content 这两个方法分别返回什么。

打印语句改成 child.content 再试试吧。
UtopiaCHN
2015-11-23 23:12:20 +08:00
@black
如果是:
for (TFHppleElement *child in e.children)
{
if ([child isTextNode])
{
NSLog(@"%@", child.content);
}
}

输出是:
2015-11-23 23:10:43.093 V2EX[34536:1463891]  • 
2015-11-23 23:10:43.093 V2EX[34536:1463891]  •  几秒前  •  最后回复来自

处理的 html :
<span class="small fade"><div class="votes"></div><a class="node" href="/go/java">Java</a> &nbsp;•&nbsp; <strong><a href="/member/kanezeng">kanezeng</a></strong> &nbsp;•&nbsp; 几秒前 &nbsp;•&nbsp; 最后回复来自 <strong><a href="/member/salmon5">salmon5</a></strong></span>
UtopiaCHN
2015-11-23 23:13:54 +08:00
@black 我刚刚写错了,换成 content 的了,是指节点标签之间的内容。
black
2015-11-23 23:17:26 +08:00
@UtopiaCHN 拿到文本后还需要处理一下字符串,解析 html 是比较麻烦的。
black
2015-11-23 23:18:15 +08:00
期待楼主的 V2EX 客户端早日上架:)
UtopiaCHN
2015-11-23 23:24:13 +08:00
@black 我也觉得,还是直接处理字符串。这是我的第一个 App ,争取下个月上架。没有处理过 html 数据,十分感谢你的耐心帮助。官方没有提供登录和评论回复的 API ,不知道该怎么实现这两个功能。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/237294

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX