注册 登录
编程论坛 VFP论坛

怎样将“VFP论坛”上发表的帖子主题下载下来

王咸美 发布于 2025-11-13 16:43, 1656 次点击
怎样将“VFP论坛”上发表的帖子主题下载下来,并写入表文件vfplt.dbf中,vfplt.dbf中字段有:序号 N(8),主题 C(60),发表 C(10),回复 N(6),人气 N(8),最后更新 C(20)
网页地址:https://bbs.bc-cn.net/forum-22-1.html
请各位高手赐教,万分感谢!!!(纯属个人爱好,不喜勿喷!全当路过)
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录
38 回复
#2
吹水佬2025-11-13 17:16
序号字段是输入什么
#3
王咸美2025-11-13 17:40
输入贴子的数量,从1开始往上递增。
#4
wengjl2025-11-14 07:46
我也曾有过这个想法,但实现不了,也就不了了之
这个想法的好处是查找方便!

静待高手解题,供吾辈学习!
#5
sam_jiang2025-11-14 12:11
回复 2楼 吹水佬
跟上次抓新浪网抓新闻标题一样,代码改改就能用
#6
iswith2025-11-14 15:51
只有本站会员才能查看附件,请 登录
#7
王咸美2025-11-14 16:09
谢谢!能分享具体代码吗?
#8
吹水佬2025-11-14 17:17
只有本站会员才能查看附件,请 登录
#9
吹水佬2025-11-14 17:25
示例只取两页作为参考
因大量处理字符串,用解析器取数据还是觉得不快,用vfp字符串函数处理就更慢。
所以用指针来试试,可能有风险,不能照抄。
程序代码:

DECLARE long URLDownloadToFileA  IN urlmon  long,string,string,long,long
DECLARE long DeleteUrlCacheEntry IN wininet string

DECLARE long malloc IN msvcrt long
DECLARE long free   IN msvcrt as _free long
DECLARE long strcpy IN msvcrt long,string
DECLARE long strstr IN msvcrt long,string

CREATE TABLE vfplt (序号 N(8), 主题 C(240), 发表 C(10), 回复 C(6), 人气 C(8), 最后更新 C(20))
n序号 = 0
url = "https://bbs.bc-/forum-22-1.html"
getPageData(getHtml(url))
url = "https://bbs.bc-/forum-22-2.html"
getPageData(getHtml(url))
SELECT * FROM vfplt

CLEAR ALL
RETURN

FUNCTION getPageData(cHtml)
    LOCAL pHtml, p
    pHtml = malloc(LEN(cHtml)+1)
    strcpy(pHtml, cHtml)
    p = pHtml
    DO WHILE p > 0
        getTextByTagName(@p, [<td class="title">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c主题 = getTextByTagName(@p, [>], [</a>])
        getTextByTagName(@p, [<td class="l_au">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c发表 = getTextByTagName(@p, [>],  [</a>])
        c回复 = getTextByTagName(@p, [<td class="l_re">], [</td>])
        c人气 = getTextByTagName(@p, [<td class="l_re">], [</td>])
        getTextByTagName(@p, [<td class="l_last">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c最后更新 = getTextByTagName(@p, [>],  [</a>])
        getTextByTagName(@p, [<a], [</a>])
        c最后更新 = c最后更新 + " " + getTextByTagName(@p, [>],  [</a>])
        n序号 = n序号 + 1
        IF !EMPTY(c主题)
            INSERT INTO vfplt VALUES (n序号, c主题, c发表, c回复, c人气, c最后更新)
        ENDIF
    ENDDO
    _free(pHtml)
ENDFUNC

FUNCTION getTextByTagName(p, cBeginTagName, cEndTagName)
    IF p == 0
        RETURN ""
    ENDIF
    p = strstr(p, cBeginTagName)
    IF p == 0
        RETURN ""
    ENDIF
    p = p + LEN(cBeginTagName)
    LOCAL p2
    p2 = strstr(p, cEndTagName)
    IF p2 == 0
        RETURN ""
    ENDIF
    RETURN SYS(2600, p, p2-p)
ENDFUNC

FUNCTION getHtml(url)
    LOCAL tmpHtml
    tmpHtml = cDefPath + "bccn_vfp.html"
    DeleteUrlCacheEntry(url)
    IF URLDownloadToFileA(0, url, tmpHtml, 0, 0)==0
        RETURN FILETOSTR(tmpHtml)
    ENDIF
    RETURN ""
ENDFUNC

#10
王咸美2025-11-14 18:02
谢谢! 如果要将整个338页全部爬下来,代码要怎么改?我想要个思路,不一定要全部爬下来。
#11
cssnet2025-11-14 18:09
以下是引用吹水佬在2025-11-14 17:25:50的发言:

示例只取两页作为参考
因大量处理字符串,用解析器取数据还是觉得不快,用vfp字符串函数处理就更慢。
所以用指针来试试,可能有风险,不能照抄。


其实,有没考虑过,之所以有时要采用最龟速的方式,一页一页慢吞吞地爬取网页(注:只需抓取少量网页,比如说,一、二百页的前提下),刻意模拟浏览器的正常点击,然后显示网页,其主要目的是规避被目标网站屏蔽、拉黑的风险。
否则的话,为什么不直接采用 WebZip 之类老牌、成熟的解决方案,却要自己费力写网页抓取代码?
#12
吹水佬2025-11-14 18:28
这类问题没有通式
能快时你会让其慢吗?
#13
nbwww2025-11-14 19:00
吹版,用你的 WebView可以基本完整的爬取整个网站   
WebView_PrintToPDF(cDefPath+STREXTRACT(bccn.url,'/','html',3)+"pdf")

#14
nbwww2025-11-14 19:02
回复 13楼 nbwww
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2025-11-14 19:04编辑过]

#15
nbwww2025-11-14 19:05
就是因为上面这个主题,那个时候把近几年的都爬下来了
#16
吹水佬2025-11-14 19:21
以下是引用王咸美在2025-11-14 18:02:35的发言:

谢谢! 如果要将整个338页全部爬下来,代码要怎么改?我想要个思路,不一定要全部爬下来。

话头画公仔都画出肠
我的变少少就是 for i=1 to 2
你的再变变就是 for i=1 to 338


#17
王咸美2025-11-14 19:31
@吹水佬:首先表示感谢!我运行程序出现下列错误,不知为何?如何修正,盼指点!
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录
#18
cssnet2025-11-14 19:50
以下是引用吹水佬在2025-11-14 18:28:51的发言:

这类问题没有通式
能快时你会让其慢吗?


不是快慢的问题。
以前我一般会提取某个小说目录网页的全部静态链接,然后用迅雷、网络蚂蚁批量下载,速度飞快!
后来发觉不行了,现在的网站似乎自动屏蔽了非浏览器正常点击的程序化访问,特别是批量断点续传下载的软件访问——于是特意慢速模拟正常点击访问。
正所谓,欲速则不达!——有时老祖宗的教训是有道理的。

#19
王咸美2025-11-14 19:55
只有本站会员才能查看附件,请 登录
#20
吹水佬2025-11-14 20:22
回复 19楼 王咸美
不要照抄
第1个异常是路径问题,要根据自己的去做。
出现异常即时“取消”退出,继续探讨。

#21
吹水佬2025-11-14 20:25
试了一下338页也不用多少时间。
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录

程序代码:

DECLARE long URLDownloadToFileA  IN urlmon  long,string,string,long,long
DECLARE long DeleteUrlCacheEntry IN wininet string

DECLARE long malloc IN msvcrt long
DECLARE long free   IN msvcrt as _free long
DECLARE long strcpy IN msvcrt long,string
DECLARE long strstr IN msvcrt long,string

CREATE TABLE vfplt (序号 N(8), 主题 C(240), 发表 C(20), 回复 C(6), 人气 C(8), 最后更新 C(30))
n序号 = 0
FOR i=1 TO 338
    url = "https://bbs.bc-/forum-22-" + TRANSFORM(i) + ".html"
    getPageData(getHtml(url))
    ?? url + 0h0D
ENDFOR
SELECT * FROM vfplt
CLEAR ALL
RETURN

FUNCTION getPageData(cHtml)
    LOCAL pHtml, p
    pHtml = _malloc(LEN(cHtml)+1)
    IF pHtml == 0
        RETURN
    ENDIF
    strcpy(pHtml, cHtml)
    p = pHtml
    DO WHILE p > 0
        getTextByTagName(@p, [<td class="title">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c主题 = getTextByTagName(@p, [>], [</a>])
        getTextByTagName(@p, [<td class="l_au">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c发表 = getTextByTagName(@p, [>],  [</a>])
        c回复 = getTextByTagName(@p, [<td class="l_re">], [</td>])
        c人气 = getTextByTagName(@p, [<td class="l_re">], [</td>])
        getTextByTagName(@p, [<td class="l_last">], [</td>])
        getTextByTagName(@p, [<a], [</a>])
        c最后更新 = getTextByTagName(@p, [>],  [</a>])
        getTextByTagName(@p, [<a], [</a>])
        c最后更新 = c最后更新 + " " + getTextByTagName(@p, [>],  [</a>])
        IF !EMPTY(c主题)
            n序号 = n序号 + 1
            INSERT INTO vfplt VALUES (n序号, c主题, c发表, c回复, c人气, c最后更新)
        ENDIF
    ENDDO
    _free(pHtml)
ENDFUNC

FUNCTION getTextByTagName(p, cBeginTagName, cEndTagName)
    IF p == 0
        RETURN ""
    ENDIF
    p = strstr(p, cBeginTagName)
    IF p == 0
        RETURN ""
    ENDIF
    p = p + LEN(cBeginTagName)
    LOCAL p2
    p2 = strstr(p, cEndTagName)
    IF p2 == 0
        RETURN ""
    ENDIF
    RETURN SYS(2600, p, p2-p)
ENDFUNC

FUNCTION getHtml(url)
    LOCAL tmpHtml
    tmpHtml = "C:\_temp\bccn_vfp.html"    && 临时文件要用自己的路径
    DeleteUrlCacheEntry(url)
    IF URLDownloadToFileA(0, url, tmpHtml, 0, 0)==0
        RETURN FILETOSTR(tmpHtml)
    ENDIF
    ? "下载 " + url + " 失败"
    RETURN ""
ENDFUNC

FUNCTION _malloc(nSize)
    LOCAL ptr
    ptr = malloc(nSize)
    IF ptr == 0
        ? "执行malloc()分配内存失败"
    ENDIF
    RETURN ptr
ENDFUNC



[此贴子已经被作者于2025-11-14 20:37编辑过]

#22
吹水佬2025-11-14 20:33
回复 18楼 cssnet
就系啦:不是快慢问题。
能快不快才是问题。
不给快用超级计算机也没用。
#23
王咸美2025-11-14 21:03
谢谢!问题完美解决。
#24
吹水佬2025-11-15 23:37
ie的解析器虽然是古董,但还可以用,速度相对慢少少。
程序代码:

DECLARE long URLDownloadToFileA  IN urlmon  long,string,string,long,long
DECLARE long DeleteUrlCacheEntry IN wininet string

dom = CREATEOBJECT("htmlfile")

CREATE TABLE vfplt (序号 N(8), 主题 C(240), 发表 C(30), 回复 C(6), 人气 C(8), 最后更新 C(30))
n序号 = 0
FOR i=1 TO 1  && 338
    url = "https://bbs.bc-/forum-22-" + TRANSFORM(i) + ".html"
    getPageData(getHtml(url))
    ?? url + 0h0D
ENDFOR
SELECT * FROM vfplt
CLEAR ALL
RETURN

FUNCTION getPageData(cHtml)
    cHtml = STRTRAN(cHtml, "<script", "<soript")
    dom.write(cHtml)
    tables = dom.getElementsByTagName("table")   
    FOR EACH table IN tables
        IF table.classname == "table_l"
            FOR EACH tr IN table.rows
                IF tr.cells[1].classname == "title"  AND ;
                   tr.cells[2].classname == "l_au"   AND ;
                   tr.cells[3].classname == "l_re"   AND ;
                   tr.cells[4].classname == "l_re"   AND ;
                   tr.cells[5].classname == "l_last"
                   n序号 = n序号 + 1
                   INSERT INTO vfplt VALUES (;
                       n序号,;
                       tr.cells[1].innertext,;                        && 主题
                       STRTRAN(tr.cells[2].innertext, 0h0D0A, "  "),; && 发表
                       tr.cells[3].innertext,;                        && 回复
                       tr.cells[4].innertext,;                        && 人气
                       STRTRAN(tr.cells[5].innertext, 0h0D0A, "  ");  && 最后更新
                   )
                ENDIF
            ENDFOR
        ENDIF
    ENDFOR
    dom.close
ENDFUNC

FUNCTION getHtml(url)
    LOCAL tmpHtml
    tmpHtml = "C:\_temp\bccn_vfp.html"
    DeleteUrlCacheEntry(url)
    IF URLDownloadToFileA(0, url, tmpHtml, 0, 0)==0
        RETURN FILETOSTR(tmpHtml)
    ENDIF
    ? "下载 " + url + " 失败"
    RETURN ""
ENDFUNC
#25
sych2025-11-16 08:26
很实用,谢谢分享
#26
hsfisher2025-11-17 08:32
#27
wengjl2025-11-18 13:01
以下是引用吹水佬在2025-11-15 23:37:16的发言:

ie的解析器虽然是古董,但还可以用,速度相对慢少少。

DECLARE long URLDownloadToFileA  IN urlmon  long,string,string,long,long
DECLARE long DeleteUrlCacheEntry IN wininet string

dom = CREATEOBJECT("htmlfile")

CREATE TABLE vfplt (序号 N(8), 主题 C(240), 发表 C(30), 回复 C(6), 人气 C(8), 最后更新 C(30))
n序号 = 0
FOR i=1 TO 1  && 338
    url = "https://bbs.bc-cn.net/forum-22-" + TRANSFORM(i) + ".html"
    getPageData(getHtml(url))
    ?? url + 0h0D
ENDFOR
SELECT * FROM vfplt
CLEAR ALL
RETURN

FUNCTION getPageData(cHtml)
    cHtml = STRTRAN(cHtml, "<script", "<soript")
    dom.write(cHtml)
    tables = dom.getElementsByTagName("table")   
    FOR EACH table IN tables
        IF table.classname == "table_l"
            FOR EACH tr IN table.rows
                IF tr.cells[1].classname == "title"  AND ;
                   tr.cells[2].classname == "l_au"   AND ;
                   tr.cells[3].classname == "l_re"   AND ;
                   tr.cells[4].classname == "l_re"   AND ;
                   tr.cells[5].classname == "l_last"
                   n序号 = n序号 + 1
                   INSERT INTO vfplt VALUES (;
                       n序号,;
                       tr.cells[1].innertext,;                        && 主题
                       STRTRAN(tr.cells[2].innertext, 0h0D0A, "  "),; && 发表
                       tr.cells[3].innertext,;                        && 回复
                       tr.cells[4].innertext,;                        && 人气
                       STRTRAN(tr.cells[5].innertext, 0h0D0A, "  ");  && 最后更新
                   )
                ENDIF
            ENDFOR
        ENDIF
    ENDFOR
    dom.close
ENDFUNC

FUNCTION getHtml(url)
    LOCAL tmpHtml
    tmpHtml = "C:\_temp\bccn_vfp.html"
    DeleteUrlCacheEntry(url)
    IF URLDownloadToFileA(0, url, tmpHtml, 0, 0)==0
        RETURN FILETOSTR(tmpHtml)
    ENDIF
    ? "下载 " + url + " 失败"
    RETURN ""
ENDFUNC


我下来试用,被提示:“下载......失败”。不知道何故了!
#28
王咸美2025-11-18 13:07
我用的IE浏览器,将https改为http,能顺利下载。
#29
吹水佬2025-11-18 13:18
以下是引用wengjl在2025-11-18 13:01:13的发言:

我下来试用,被提示:“下载......失败”。不知道何故了!

一字不改照做吗:"C:\_temp\bccn_vfp.html"
#30
wengjl2025-11-18 13:48
以下是引用吹水佬在2025-11-18 13:18:52的发言:


一字不改照做吗:"C:\_temp\bccn_vfp.html"


我在C盘 建立“_temp”文件夹,在目录中测试的。浏览器是360的。win7+vfp8.0


#31
wengjl2025-11-18 13:51
只有本站会员才能查看附件,请 登录
#32
王咸美2025-11-18 18:54
用21楼代码试试看
#33
吹水佬2025-11-18 19:23
回复 31楼 wengjl
如果是vfp9应该不是 ??url+0h0D 语句出错
试试跟踪调试或逐渐中断执行观察一下到那条语句出错。

#34
wengjl2025-11-19 08:40
环境是 win7 + vfp8.0
#35
吹水佬2025-11-19 09:45
以下是引用wengjl在2025-11-19 08:40:10的发言:

环境是 win7 + vfp8.0


没用过vfp8
vfp8支持0h0D表达式吗?
不支持就改用chr(13)

#36
wengjl2025-11-19 10:27
将 0h0D 换成 chr(13),结果如图。不知如何是好了
只有本站会员才能查看附件,请 登录


是360浏览器

gethtml() 无返回值

[此贴子已经被作者于2025-11-19 10:36编辑过]

#37
wengjl2025-11-19 10:41
以下是引用王咸美在2025-11-18 18:54:04的发言:

用21楼代码试试看


用这个不会停,但显示 下载...失败
#38
wengjl2025-11-20 08:12
向 吹版 报告:昨晚回家测试,VF8不能识别 0h0D0A ,后改用21楼代码,顺利完成任务。

猜想,公司的电脑无法完成,可能是公司电脑有加密的原因吧!

感谢吹版的热心帮助,谢谢!
#39
吹水佬2025-11-20 09:41
回复 38楼 wengjl
下载...失败 可能公司不给你随便出去遛
1