【问题标题】:retrieving text from a website with goquery使用 goquery 从网站检索文本
【发布时间】:2017-12-21 20:50:25
【问题描述】:

我的 html 大致如下所示:

<h4>Movies</h4>
    <h5><a href="external_link" target="_blank"> A Song For Jenny</a> (2015)</h5>
    Rating: PG<br/>
    Running Time (minutes): 77<br/>
    Description: This Drama, based on real life events, tells the story of a family affected directly by the 7/7 London bombings.  It shows love, loss, heartache and  ...<br/>
    <a href="/bmm/shop/Movie_Detail?movieid=2713288">More about  A Song For Jenny</a><br/>
        <a href="/bmm/shop/Edit_Movie?movieid=2713288">Edit  A Song For Jenny</a><br/>
    <br/>
    <h5><a href="link" target="_blank">#RealityHigh</a> (2017)</h5>
    Rating: PG<br/>
    Running Time (minutes): 99<br/>
    Description: High-achieving high-school senior Dani Barnes dreams of getting into UC Davis, the world's top  veterinary school. Then a glamorous new friend draws  ...<br/>
    <a href="/bmm/shop/Movie_Detail?movieid=4089906">More about #RealityHigh</a><br/>
        <a href="/bmm/shop/Edit_Movie?movieid=4089906">Edit #RealityHigh</a><br/>
    <br/>
    <h5><a href="link" target="_blank">1 Night</a> (2016)</h5>
    Rating: PG<br/>
    Running Time (minutes): 80<br/>
    Description: Bea, a worrisome teenager, reconnects with her introverted childhood friend, Andy. The two  overcome their differences in social status one night aft ...<br/>
    <a href="/bmm/shop/Movie_Detail?movieid=3959071">More about 1 Night</a><br/>
        <a href="/bmm/shop/Edit_Movie?movieid=3959071">Edit 1 Night</a><br/>
    <br/>
    <h5><a href="link" target="_blank">10 Cloverfield Lane</a> (2016)</h5>
    Rating: PG<br/>
    Running Time (minutes): 104<br/>
    Description: Soon after leaving her fiancé Michelle is involved in a car accident. She awakens
to find herself sharing an underground bunker with Howard and Emme ...<br/>
    <a href="/bmm/shop/Movie_Detail?movieid=3052189">More about 10 Cloverfield Lane</a><br/>
        <a href="/bmm/shop/Edit_Movie?movieid=3052189">Edit 10 Cloverfield Lane</a><br/>
    <br/>

我需要使用 goquery 从该页面中获取尽可能多的信息。我知道如何提取在此片段中用“链接”一词替换的外部链接,我知道如何获取更多详细信息的链接,但我也想提取仅包含在文本中的信息,即年份(在标题中) ,运行时间,缩短描述和PG等级。 我无法弄清楚如何在 goquery 中执行此操作,因为此文本没有被任何 div 或其他标签包围。我尝试查找 h5 标签,然后在它们上调用 .Next() 但我只能找到 &lt;br&gt; 标签,而不是中间的文本。我怎样才能做到这一点?如果有比使用 goquery 更好的方法,我很好。 我的代码如下所示。

// Retrieve the page count:
    res, err = http.Get("myUrlAddress")
    if err != nil {
        fmt.Println(err)
        os.Exit(-1)
    }
    doc, err = goquery.NewDocumentFromResponse(res)
    if err != nil {
        fmt.Println(err)
        os.Exit(-1)
    }
    links := doc.Find(`a[href*="pageIndex"]`)
    fmt.Println(links.Length()) // Output page count
s := doc.Find("h5").First().Next() // I expect it to be the text after the heading.
fmt.Println(s.Text()) // But it's empty and if I check the node type it says br

【问题讨论】:

  • 请包含您当前的代码,说明您遇到了什么问题,以及您的预期。
  • 完成,刚刚编辑了问题
  • 我认为这会很难,因为您要提取的文本不在Document 节点中。另一种选择是使用regex 提取它。

标签: html go goquery


【解决方案1】:

我不喜欢使用正则表达式解析 html 的想法。我觉得它对于标签顺序或类似的小变化太脆弱了。

我认为最好还是使用 goquery 所基于的 html.Node(golang.org/x/net/html)。这个想法是迭代兄弟姐妹,直到它用完,或者遇到下一个h5。处理链接或任何其他元素标签可能有点麻烦,因为 html.Node 提供了一个关于属性的相当不友好的 api,但从它切换回 goquery 更麻烦。

package main

import (
    "fmt"
    "github.com/PuerkitoBio/goquery"
    "golang.org/x/net/html"
    "golang.org/x/net/html/atom"
    "os"
    "strings"
)

type Movie struct {
}

func (m Movie) addTitle(s string) {
    fmt.Println("Title", s)
}

func (m Movie) addProperty(s string) {
    if s == "" {
        return
    }
    fmt.Println("Property", s)
}

var M []*Movie

func parseMovie(i int, s *goquery.Selection) {
    m := &Movie{}
    m.addTitle(s.Text())

loop:
    for node := s.Nodes[0].NextSibling; node != nil; node = node.NextSibling {
        switch node.Type {
        case html.TextNode:
            m.addProperty(strings.TrimSpace(node.Data))
        case html.ElementNode:
            switch node.DataAtom {
            case atom.A:
                //link, do something. You may want to transfer back to go query
                fmt.Println(node.Attr)
            case atom.Br:
                continue
            case atom.H5:
                break loop
            }
        }
    }

    M = append(M, m)
}

func main() {
    r, err := os.Open("movie.html")
    if err != nil {
        panic(err)
    }
    doc, err := goquery.NewDocumentFromReader(r)
    if err != nil {
        panic(err)
    }

    doc.Find("h5").Each(parseMovie)
}

【讨论】:

    【解决方案2】:

    不幸的是,由于此 HTML 页面的结构,在您确定示例中包含电影列表的页面部分后,goquery 似乎没有太大帮助,因为感兴趣的数据点不会被隔离到可以被 goquery 定位的元素中。

    但是,使用正则表达式可以轻松解析详细信息,当然可以根据需要进行修改(尤其是当/当原始页面更改其 HTML 结构时)。

    type Movie struct {
        Title          string
        ReleaseYear    int
        Rating         string
        RuntimeMinutes int
        Description    string
    }
    
    var movieregexp = regexp.MustCompile(`` +
        `<h5><a.*?>\s*(.*?)\s*</a>\s*\((\d{4})\)</h5>` + // Title and release year
        `[\s\S]*?Rating: (.*?)<` +
        `[\s\S]*?Running Time \(minutes\): (\d{1,3})` +
        `[\s\S]*?Description: ([\s\S]*?)<`)
    
    // Returns a slice of movies parsed from the given string, possibly empty.
    func ParseMovies(s string) []Movie {
        movies := []Movie{}
        groups := movieregexp.FindAllStringSubmatch(s, -1)
    
        if groups != nil {
            for _, group := range groups {
                // We know these integers parse correctly because of the regex.
                year, _ := strconv.Atoi(group[2])
                runtime, _ := strconv.Atoi(group[4])
                // Append the new movie to the list.
                movies = append(movies, Movie{
                    Title:          group[1],
                    ReleaseYear:    year,
                    Rating:         group[3],
                    RuntimeMinutes: runtime,
                    Description:    group[5],
                })
            }
        }
    
        return movies
    }
    

    【讨论】:

    • 这就是我最后所做的。我使用了 html 节点并直接对它们进行了处理(围绕原始网站的愚蠢和怪癖进行了很多黑客攻击)。我的代码将在几天后登陆 github,届时我会在 cmets 中添加指向它的链接。
    猜你喜欢
    • 1970-01-01
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-25
    相关资源
    最近更新 更多