232 lines
5.9 KiB
Go
232 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func main() {
|
|
// 打开数据库
|
|
db, err := sql.Open("sqlite", "../../data/wechat_articles.db")
|
|
if err != nil {
|
|
log.Fatal("打开数据库失败:", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
fmt.Println("=" + repeatStr("=", 80))
|
|
fmt.Println("📊 微信公众号文章数据库内容查看")
|
|
fmt.Println("=" + repeatStr("=", 80))
|
|
|
|
// 查询公众号
|
|
fmt.Println("\n📢 【公众号列表】")
|
|
fmt.Println(repeatStr("-", 80))
|
|
queryOfficialAccounts(db)
|
|
|
|
// 查询文章
|
|
fmt.Println("\n📝 【文章列表】")
|
|
fmt.Println(repeatStr("-", 80))
|
|
queryArticles(db)
|
|
|
|
// 查询文章内容
|
|
fmt.Println("\n📄 【文章详细内容】")
|
|
fmt.Println(repeatStr("-", 80))
|
|
queryArticleContents(db)
|
|
|
|
fmt.Println("\n" + repeatStr("=", 80))
|
|
}
|
|
|
|
func queryOfficialAccounts(db *sql.DB) {
|
|
rows, err := db.Query(`
|
|
SELECT id, biz, nickname, homepage, description, created_at, updated_at
|
|
FROM official_accounts
|
|
ORDER BY id
|
|
`)
|
|
if err != nil {
|
|
log.Printf("查询公众号失败: %v\n", err)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := 0
|
|
for rows.Next() {
|
|
var id int
|
|
var biz, nickname, homepage, description, createdAt, updatedAt string
|
|
err := rows.Scan(&id, &biz, &nickname, &homepage, &description, &createdAt, &updatedAt)
|
|
if err != nil {
|
|
log.Printf("读取数据失败: %v\n", err)
|
|
continue
|
|
}
|
|
count++
|
|
|
|
fmt.Printf("\n🔹 公众号 #%d\n", id)
|
|
fmt.Printf(" 名称: %s\n", nickname)
|
|
fmt.Printf(" BIZ: %s\n", biz)
|
|
fmt.Printf(" 主页: %s\n", homepage)
|
|
fmt.Printf(" 简介: %s\n", description)
|
|
fmt.Printf(" 创建时间: %s\n", createdAt)
|
|
fmt.Printf(" 更新时间: %s\n", updatedAt)
|
|
}
|
|
|
|
if count == 0 {
|
|
fmt.Println(" 暂无数据")
|
|
} else {
|
|
fmt.Printf("\n总计: %d 个公众号\n", count)
|
|
}
|
|
}
|
|
|
|
func queryArticles(db *sql.DB) {
|
|
rows, err := db.Query(`
|
|
SELECT a.id, a.official_id, a.title, a.author, a.link, a.publish_time,
|
|
a.read_num, a.like_num, a.share_num, a.paragraph_count,
|
|
a.content_preview, a.created_at, oa.nickname
|
|
FROM articles a
|
|
LEFT JOIN official_accounts oa ON a.official_id = oa.id
|
|
ORDER BY a.id
|
|
`)
|
|
if err != nil {
|
|
log.Printf("查询文章失败: %v\n", err)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := 0
|
|
for rows.Next() {
|
|
var id, officialID, readNum, likeNum, shareNum, paragraphCount int
|
|
var title, author, link, publishTime, contentPreview, createdAt, officialName sql.NullString
|
|
err := rows.Scan(&id, &officialID, &title, &author, &link, &publishTime,
|
|
&readNum, &likeNum, &shareNum, ¶graphCount, &contentPreview, &createdAt, &officialName)
|
|
if err != nil {
|
|
log.Printf("读取数据失败: %v\n", err)
|
|
continue
|
|
}
|
|
count++
|
|
|
|
fmt.Printf("\n🔹 文章 #%d\n", id)
|
|
fmt.Printf(" 标题: %s\n", getStringValue(title))
|
|
if officialName.Valid {
|
|
fmt.Printf(" 公众号: %s\n", officialName.String)
|
|
}
|
|
fmt.Printf(" 作者: %s\n", getStringValue(author))
|
|
fmt.Printf(" 链接: %s\n", getStringValue(link))
|
|
fmt.Printf(" 发布时间: %s\n", getStringValue(publishTime))
|
|
fmt.Printf(" 阅读数: %d | 点赞数: %d | 分享数: %d\n", readNum, likeNum, shareNum)
|
|
fmt.Printf(" 段落数: %d\n", paragraphCount)
|
|
if contentPreview.Valid && contentPreview.String != "" {
|
|
preview := contentPreview.String
|
|
if len(preview) > 100 {
|
|
preview = preview[:100] + "..."
|
|
}
|
|
fmt.Printf(" 内容预览: %s\n", preview)
|
|
}
|
|
fmt.Printf(" 抓取时间: %s\n", getStringValue(createdAt))
|
|
}
|
|
|
|
if count == 0 {
|
|
fmt.Println(" 暂无数据")
|
|
} else {
|
|
fmt.Printf("\n总计: %d 篇文章\n", count)
|
|
}
|
|
}
|
|
|
|
func queryArticleContents(db *sql.DB) {
|
|
rows, err := db.Query(`
|
|
SELECT ac.id, ac.article_id, ac.html_content, ac.text_content,
|
|
ac.paragraphs, ac.images, ac.created_at, a.title
|
|
FROM article_contents ac
|
|
LEFT JOIN articles a ON ac.article_id = a.id
|
|
ORDER BY ac.id
|
|
`)
|
|
if err != nil {
|
|
log.Printf("查询文章内容失败: %v\n", err)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := 0
|
|
for rows.Next() {
|
|
var id, articleID int
|
|
var htmlContent, textContent, paragraphs, images, createdAt, title sql.NullString
|
|
err := rows.Scan(&id, &articleID, &htmlContent, &textContent,
|
|
¶graphs, &images, &createdAt, &title)
|
|
if err != nil {
|
|
log.Printf("读取数据失败: %v\n", err)
|
|
continue
|
|
}
|
|
count++
|
|
|
|
fmt.Printf("\n🔹 内容 #%d (文章ID: %d)\n", id, articleID)
|
|
if title.Valid {
|
|
fmt.Printf(" 文章标题: %s\n", title.String)
|
|
}
|
|
|
|
// HTML内容长度
|
|
htmlLen := 0
|
|
if htmlContent.Valid {
|
|
htmlLen = len(htmlContent.String)
|
|
}
|
|
fmt.Printf(" HTML内容长度: %d 字符\n", htmlLen)
|
|
|
|
// 文本内容
|
|
if textContent.Valid && textContent.String != "" {
|
|
text := textContent.String
|
|
if len(text) > 200 {
|
|
text = text[:200] + "..."
|
|
}
|
|
fmt.Printf(" 文本内容: %s\n", text)
|
|
}
|
|
|
|
// 段落信息
|
|
if paragraphs.Valid && paragraphs.String != "" {
|
|
var paragraphList []interface{}
|
|
if err := json.Unmarshal([]byte(paragraphs.String), ¶graphList); err == nil {
|
|
fmt.Printf(" 段落数量: %d\n", len(paragraphList))
|
|
}
|
|
}
|
|
|
|
// 图片信息
|
|
if images.Valid && images.String != "" {
|
|
var imageList []interface{}
|
|
if err := json.Unmarshal([]byte(images.String), &imageList); err == nil {
|
|
fmt.Printf(" 图片数量: %d\n", len(imageList))
|
|
if len(imageList) > 0 {
|
|
fmt.Printf(" 图片URL:\n")
|
|
for i, img := range imageList {
|
|
if i >= 3 {
|
|
fmt.Printf(" ... 还有 %d 张图片\n", len(imageList)-3)
|
|
break
|
|
}
|
|
fmt.Printf(" %d. %v\n", i+1, img)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Printf(" 存储时间: %s\n", getStringValue(createdAt))
|
|
}
|
|
|
|
if count == 0 {
|
|
fmt.Println(" 暂无数据")
|
|
} else {
|
|
fmt.Printf("\n总计: %d 条详细内容\n", count)
|
|
}
|
|
}
|
|
|
|
func getStringValue(s sql.NullString) string {
|
|
if s.Valid {
|
|
return s.String
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func repeatStr(s string, n int) string {
|
|
result := ""
|
|
for i := 0; i < n; i++ {
|
|
result += s
|
|
}
|
|
return result
|
|
}
|