Go 爬虫抓取解析 xml
导入爬虫用到的库
import ( "encoding/xml" // xml 标准库 "fmt" // 打印" "io/ioutil" // ioutil 包实现了一些 I/O 实用函数。 "net/http" // http 请求库 )
1
2
3
4
5
6
7
8
9
10
11
|
import
(
"encoding/xml"
/
/
xml
标准库
"fmt"
/
/
打印
"
"
io
/
ioutil
"
// ioutil 包实现了一些 I/O 实用函数。
"
net
/
http"
/
/
http
请求库
)
|
定义抓取函数
// 抓取 url xml 返回 []byte func getXML(url string) ([]byte, error) { resp, err := http.Get(url) // 请求 url if err != nil { return []byte{}, fmt.Errorf("GET error: %v", err) } defer resp.Body.Close() // 清理内存 if resp.StatusCode != http.StatusOK { return []byte{}, fmt.Errorf("Status error: %v", resp.StatusCode) } // 根据状态码 判断是否正常 data, err := ioutil.ReadAll(resp.Body) if err != nil { return []byte{}, fmt.Errorf("Read body: %v", err) } return data, nil }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/
/
抓取
url
xml
返回
[
]
byte
func
getXML
(
url
string
)
(
[
]
byte
,
error
)
{
resp
,
err
:
=
http
.
Get
(
url
)
/
/
请求
url
if
err
!=
nil
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"GET error: %v"
,
err
)
}
defer
resp
.
Body
.
Close
(
)
/
/
清理内存
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"Status error: %v"
,
resp
.
StatusCode
)
}
/
/
根据状态码
判断是否正常
data
,
err
:
=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"Read body: %v"
,
err
)
}
return
data
,
nil
}
|
xml 格式
定义xml 的 struct
type rss struct { XMLName xml.Name `xml:"rss"` Items []itemD `xml:"channel>item"` } type itemD struct { Title string `xml:"title"` PubDate string `xml:"pubDate"` Link string `xml:"link"` }
1
2
3
4
5
6
7
8
9
10
11
|
type
rss
struct
{
XMLName
xml
.
Name
`
xml
:
"rss"
`
Items
[
]
itemD
`
xml
:
"channel>item"
`
}
type
itemD
struct
{
Title
string
`
xml
:
"title"
`
PubDate
string
`
xml
:
"pubDate"
`
Link
string
`
xml
:
"link"
`
}
|
struct 和 xml 格式对应
rss struct 对应 xml
itemD struct 对应 xml
主函数
func main() { url :="https://rsshub.app/fx678/kx" bytes,_:= getXML(url) var ss rss xml.Unmarshal(bytes,&ss) // 解包 for index, value := range ss.Items{ fmt.Println(index,value.Link, value.PubDate, value.Title) } // 由于 ss.Items 是个数组,所以采用 for 循环遍历 }
1
2
3
4
5
6
7
8
9
10
11
12
13
|
func
main
(
)
{
url
:
=
"https://rsshub.app/fx678/kx"
bytes
,
_
:
=
getXML
(
url
)
var
ss
rss
xml
.
Unmarshal
(
bytes
,
&
ss
)
/
/
解包
for
index
,
value
:
=
range
ss
.
Items
{
fmt
.
Println
(
index
,
value
.
Link
,
value
.
PubDate
,
value
.
Title
)
}
/
/
由于
ss
.
Items
是个数组,所以采用
for
循环遍历
}
|
输出如下:
全部代码如下:
package main import ( "encoding/xml" "fmt" "io/ioutil" "net/http" ) // 抓取 url xml 返回 []byte func getXML(url string) ([]byte, error) { resp, err := http.Get(url) // 请求 url if err != nil { return []byte{}, fmt.Errorf("GET error: %v", err) } defer resp.Body.Close() // 清理内存 if resp.StatusCode != http.StatusOK { return []byte{}, fmt.Errorf("Status error: %v", resp.StatusCode) } // 根据状态码 判断是否正常 data, err := ioutil.ReadAll(resp.Body) if err != nil { return []byte{}, fmt.Errorf("Read body: %v", err) } return data, nil } type rss struct { XMLName xml.Name `xml:"rss"` Items []itemD `xml:"channel>item"` } type itemD struct { Title string `xml:"title"` PubDate string `xml:"pubDate"` Link string `xml:"link"` } // 变量一定要大写 // 定义结构体 func main() { url :="https://rsshub.app/fx678/kx" bytes,_:= getXML(url) var ss rss xml.Unmarshal(bytes,&ss) for index, value := range ss.Items{ fmt.Println(index,value.Link, value.PubDate, value.Title) } // 由于 ss.Items 是个数组,所以采用 for 循环遍历 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package
main
import
(
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
)
/
/
抓取
url
xml
返回
[
]
byte
func
getXML
(
url
string
)
(
[
]
byte
,
error
)
{
resp
,
err
:
=
http
.
Get
(
url
)
/
/
请求
url
if
err
!=
nil
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"GET error: %v"
,
err
)
}
defer
resp
.
Body
.
Close
(
)
/
/
清理内存
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"Status error: %v"
,
resp
.
StatusCode
)
}
/
/
根据状态码
判断是否正常
data
,
err
:
=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
[
]
byte
{
}
,
fmt
.
Errorf
(
"Read body: %v"
,
err
)
}
return
data
,
nil
}
type
rss
struct
{
XMLName
xml
.
Name
`
xml
:
"rss"
`
Items
[
]
itemD
`
xml
:
"channel>item"
`
}
type
itemD
struct
{
Title
string
`
xml
:
"title"
`
PubDate
string
`
xml
:
"pubDate"
`
Link
string
`
xml
:
"link"
`
}
/
/
变量一定要大写
/
/
定义结构体
func
main
(
)
{
url
:
=
"https://rsshub.app/fx678/kx"
bytes
,
_
:
=
getXML
(
url
)
var
ss
rss
xml
.
Unmarshal
(
bytes
,
&
ss
)
for
index
,
value
:
=
range
ss
.
Items
{
fmt
.
Println
(
index
,
value
.
Link
,
value
.
PubDate
,
value
.
Title
)
}
/
/
由于
ss
.
Items
是个数组,所以采用
for
循环遍历
}
|
另外一个库 更方便 etree
package main import ( "fmt" "github.com/levigross/grequests" ) import "github.com/beevik/etree" func main() { url := "https://rsshub.app/fx678/kx" xml_source, _ := grequests.Get(url, nil) doc := etree.NewDocument() if err := doc.ReadFromString(xml_source.String()); err != nil { panic(err) } root := doc.SelectElement("rss") root = root.SelectElement("channel") for _, item := range root.SelectElements("item") { title := item.SelectElement("title").Text() url := item.SelectElement("link").Text() fmt.Println(title, url) } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
main
import
(
"fmt"
"github.com/levigross/grequests"
)
import
"github.com/beevik/etree"
func
main
(
)
{
url
:
=
"https://rsshub.app/fx678/kx"
xml_source
,
_
:
=
grequests
.
Get
(
url
,
nil
)
doc
:
=
etree
.
NewDocument
(
)
if
err
:
=
doc
.
ReadFromString
(
xml_source
.
String
(
)
)
;
err
!=
nil
{
panic
(
err
)
}
root
:
=
doc
.
SelectElement
(
"rss"
)
root
=
root
.
SelectElement
(
"channel"
)
for
_
,
item
:
=
range
root
.
SelectElements
(
"item"
)
{
title
:
=
item
.
SelectElement
(
"title"
)
.
Text
(
)
url
:
=
item
.
SelectElement
(
"link"
)
.
Text
(
)
fmt
.
Println
(
title
,
url
)
}
}
|