【问题标题】:Golang table webscrapingGolang 表格抓取
【发布时间】:2022-11-05 23:02:04
【问题描述】:

我有如下代码来从 html 表中抓取特定的单元格值。您可以访问https://www.haremaltin.com/altin-fiyatlari 网站并在检查模式下搜索“satis__ATA_ESKI”以查看该值。我是 golang 的初学者并且尽了最大努力,但不幸的是我无法获得那个价值。有没有人可以帮助我?顺便说一句,他们没有社区 api。还有一件事,添加 time.sleep 以等待页面加载。如果它返回“-”那是因为页面还没有被加载

package main

import (
"fmt"
"log"
"net/http"

"github.com/PuerkitoBio/goquery"
)

func main() {
   url := "https://www.haremaltin.com/altin-fiyatlari"

   resp, err := http.Get(url)
   if err != nil {
       log.Fatal(err)
   }
   defer resp.Body.Close()
   if resp.StatusCode != 200 {
       log.Fatalf("failed to fetch data: %d %s", resp.StatusCode, resp.Status)
   }

   doc, err := goquery.NewDocumentFromReader(resp.Body)
   if err != nil {
      log.Fatal(err)
   }

   doc.Find("tr__ATA_ESKI tr").Each(func(j int, tr *goquery.Selection) {
      data := []string{}
      tr.Find("td").Each(func(ix int, td *goquery.Selection) {
           e := td.Text()
           data = append(data, e)
           fmt.Println(data)
      })
   })
}

解决方案:

您可以在下面看到答案,如果您愿意,可以查看 了解为什么使用这种解决方案

顺便说一句,我们可以使用迭代从地图中获取特定值。我也有这个代码。但是,如果您有任何更简单的方法,请发表评论

for _, v := range data { // we need value part of the map
    m, ok := v.(map[string]interface{}) // we need the convert the map 
                                    // into interface for iteration
    if !ok {
        fmt.Printf("Error %T", v)
    }
    for k, l := range m {
        if k == "ATA_ESKI"{ // the value we want is inside of this map
            a, ok := l.(map[string]interface{}) // interface convert again
            if !ok {
                fmt.Printf("Error %T", v)
            }
            for b,c := range a{
                if b == "satis"{ // the value we want
                    fmt.Println("Price is", c)
                }
            }
        }
    }
}

以下迭代的完整解决方案:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "strings"
)

func main() {
    fecthData()
}

func fecthData() (map[string]interface{}, error) {
    body := strings.NewReader("dil_kodu=tr")
    req, err := http.NewRequest("POST", 
"https://www.haremaltin.com/dashboard/ajax/doviz", body)
    if err != nil {
        // handle err
        return nil, err
    }
    req.Header.Set("X-Requested-With", "XMLHttpRequest")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        // handle err
        return nil, err
    }
    defer resp.Body.Close()
    jsonData, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
        return nil, err
    }

    var data map[string]interface{}
    err = json.Unmarshal(jsonData, &data)
    if err != nil {
        return nil, err
    }

    for _, v := range data {
        m, ok := v.(map[string]interface{})
        if !ok {
            fmt.Printf("Error %T", v)
        }
        for k, l := range m {
            if k == "ATA_ESKI" {
                a, ok := l.(map[string]interface{})
                if !ok {
                    fmt.Printf("Error %T", v)
                }
                for b, c := range a {
                    if b == "satis" {
                        fmt.Println("Price", c)
                    }
                }
            }
        }
    }

    return data, nil
}

【问题讨论】:

    标签: api go web-scraping html-table goquery


    【解决方案1】:

    您可以通过 http Post 请求获取。不要忘记在请求中添加 X-Requested-With 标头。

    func fecthData() (map[string]interface{}, error) {
        body := strings.NewReader("dil_kodu=tr")
        req, err := http.NewRequest("POST", "https://www.haremaltin.com/dashboard/ajax/doviz", body)
        if err != nil {
            // handle err
            return nil, err
        }
        req.Header.Set("X-Requested-With", "XMLHttpRequest")
    
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            // handle err
            return nil, err
        }
        defer resp.Body.Close()
        jsonData, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            panic(err)
            return nil, err
        }
        var data map[string]interface{}
        err = json.Unmarshal(jsonData, &data)
        if err != nil {
            return nil, err
        }
        return data, nil
    }
    

    【讨论】:

    • 太感谢了。我没想到会有这样的解决方案。检查源代码后,我的脑海中出现了一个灯泡。真的非常感谢
    【解决方案2】:

    由于该表由 javascript 提供支持,我建议您使用不同的方法。这就是为什么。

    你真正要刮的是

    curl https://www.haremaltin.com/altin-fiyatlari > out.html
    

    这个网页。您可以在终端中运行此 curl 并获得与 go 的 rest 请求完全相同的回复(在大多数情况下,exact 是一个强词,肯定是这种情况)

    正如您所见,您创建的 out.html 文件中没有任何值,这就是您的 go 脚本没有返回任何值的原因。

    您需要运行 javascript 来填充页面,然后才能抓取它。

    我在几个项目中使用了这个https://github.com/chromedp/chromedp,并取得了巨大的成功。通过使用此工具,您的工作流程将类似于..

    1. 打开无头浏览器
    2. 转到网址
    3. 转储页面 html
    4. 使用 goquery 解析
    5. 打印您的回复

    【讨论】:

    • 实际上..如果您查看网络流量,您可能会找到您正在寻找的内容,并且可以使用更简单的方法..
    • 我建议您检查解决方案
    • 是的,就是这样。并且数据应该是json
    • 实际上我试图将其转换为 json 但失败了。你知道怎么做吗?
    • @eyup.tatar 你看到了什么错误?
    【解决方案3】:

    如果您需要更结构化的方式从 HTML 表中提取数据,https://github.com/nfx/go-htmltable 确实支持行/列跨度。

    type AM4 struct {
        Model             string `header:"Model"`
        ReleaseDate       string `header:"Release date"`
        PCIeSupport       string `header:"PCIesupport[a]"`
        MultiGpuCrossFire bool   `header:"Multi-GPU CrossFire"`
        MultiGpuSLI       bool   `header:"Multi-GPU SLI"`
        USBSupport        string `header:"USBsupport[b]"`
        SATAPorts         int    `header:"Storage features SATAports"`
        RAID              string `header:"Storage features RAID"`
        AMDStoreMI        bool   `header:"Storage features AMD StoreMI"`
        Overclocking      string `header:"Processoroverclocking"`
        TDP               string `header:"TDP"`
        SupportExcavator  string `header:"CPU support[14] Excavator"`
        SupportZen        string `header:"CPU support[14] Zen"`
        SupportZenPlus    string `header:"CPU support[14] Zen+"`
        SupportZen2       string `header:"CPU support[14] Zen 2"`
        SupportZen3       string `header:"CPU support[14] Zen 3"`
        Architecture      string `header:"Architecture"`
    }
    am4Chipsets, _ := htmltable.NewSliceFromURL[AM4]("https://en.wikipedia.org/wiki/List_of_AMD_chipsets")
    fmt.Println(am4Chipsets[2].Model)
    fmt.Println(am4Chipsets[2].SupportZen2)
    
    // Output:
    // X370
    // Varies[c]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 2011-03-11
      • 2021-07-08
      • 2021-01-04
      相关资源
      最近更新 更多