zoukankan      html  css  js  c++  java
  • 用正则获取百度贴吧当日新贴

    工作中需要抓百度贴吧指定贴吧每日新贴,包括主题贴和回复贴。
    按理说百度应该给吧主提供这样的功能。但我没找到。
    百度还提供了个高级搜索功能 http://tieba.baidu.com/f/search/adv 。搜索结果可以按时间倒序排列,可惜必须设关键字或用户名。所以也不能满足需求。
    想了个变通的办法。
    1)每分钟爬一次首页,取到首页上最后回复者的用户名。
    2)使用高级搜索,设定吧名和用户名搜索并提取发贴日期为结果。

    [root@iZlmsymZ ~]$wget http://tieba.baidu.com/f?kw=%C9%BD%CE%F7 -O - | grep -Po 'href="(/p/[0-9]{10}).*?j_user_card.*?>(.*?)<.*?threadlist_reply_date j_reply_data.*?>[ ]*([0-9]{1,2}:[0-9]{2})' - | sed -r s/'href="(/p/[0-9]{10}).*?j_user_card[^>]*>([^<]*)<.*?threadlist_reply_date j_reply_data.*?>[ ]*([0-9]{1,2}:[0-9]{2})'/'1	2	3'/g

    wget -- linux 下获取 http页面的工具 -O - 表示输出到管道(而不是文件)

    grep --linux 正则表达式工具

    -P  使用 prel语法

    -o  只输出匹配到的内容(而不是一行)

    (/p/[0-9]{10}) 首页贴子的链接,格式为 a href="/p/3444444444"
    .*? 非贪婪匹配任意字符
    j_user_card.*?>(.*?) 查找发贴人昵称,值为(.*?)
    threadlist_reply_date j_reply_data.*?>[ ]*([0-9]{1,2}:[0-9]{2})  最后回复日期,值为([0-9]{1,2}:[0-9]{2})
    首页中不能获取到最新回复贴的url。为了获取最新的帖子(无论是主题还是回复),需要以到 http://tieba.baidu.com/f/search/ures? 查询。查询条件是吧名和用户名。在找到的结果中,如果发贴时间匹配,那么就可以认为是刚才在首页查到的新贴,从而采集url.
    wget http://tieba.baidu.com/f?kw=山西 -O - | grep -Po 'j_user_card.*?>.*?<' - | sed -r s/'j_user_card[^>]*>([^<]*)<'/'http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=1'/g
    j_user_card 是用户名所在的标签标识。用grep找到后,用sed提取并连接成url。结果如下:
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=佛光普照五台山
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=不见风雨见彩虹
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=★冰月寒心★
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=小伟苦笑
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=小伟苦笑
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=领域神王
    http://tieba.baidu.com/f/search/ures?ie=utf-8&kw=山西&un=chenxin0357
    ……
    [root@iZ62jhlmZ ~]$wget http://tieba.baidu.com/f?kw=山西 -O - | grep -Po 'j_user_card.*?>.*?<' - | sed -r s/'j_user_card.*?>([^<]*)<'/'/f/search/ures?ie=utf-8&kw=山西&un=1'/g | wget --base=http://tieba.baidu.com -i - -O - | grep -Po '<div class="s_post".*?class="p_green p_date".*?>' >urlcheck.txt

    上面使用 "wget -i - -O -"打开sed 组织的url,并使用grep提取相关内容到 urlcheck.txt中。 

    grep -Po '<div class="s_post".*?class="p_green p_date".*?>'

    在高级查询中查询到的记录,我们只取当天的。

    [root@iZ62jhlmsZ ~]$grep "$(date --rfc-3339='date')"

     所以,提取一个用户当天发贴的语句是:

    wget http://tieba.baidu.com/f?kw=山西 -O - | grep -Po 'j_user_card.*?>.*?<' - | sed -r s/'j_user_card.*?>([^<]*)<'/'/f/search/ures?ie=utf-8&kw=山西&un=1'/g | wget --base=http://tieba.baidu.com -i - -O - | grep -Po "<div class="s_post">.*?<font class="p_green p_date">$(date --rfc-3339='date').*?</font>" |  sed s/'^.*<a.*href="(.*)" class.*>(.*)</a>.*<div.*>(.*)</div>.*<font.*>(.*)</font>.*<font.*>.*([-0-9: ]{16})</font>.*$'/'1	2	3	4	5'/g

     实际sed操作会出错,试着转成utf-8编码就正常了。

     iconv --from-code=latin1 --to-code=utf-8

    原因解释:

    "sed的执行会和locale相关。比如说如果文件的编码是gbk的,而locale是utf-8,这时候你所有关于正则表达式的知识都是不起作用的。根据我的经验用sed处理有中文字符处理的文件,最好把locale设置成LC_ALL=C,进行处理,或者你能保证文件的编码和locale是一致的情况下。" 

    export LC_ALL=C

    推荐使用 LC_ALL=C 因为转成utf-8会严重影响正则匹配的效率。

    sed 的另一个问题是它不支持非贪婪匹配。所以在书写的时候费了很大周折。

    另外还得删除重复的记录。

    awk '!a[$0]{a[$0]=1;print  "/f/search/ures?rn=10&ie=utf-8&kw=山西&un="$0}' ./tiebaapp/tiebaactiveuser.lst&& :>./tiebaapp/tiebaactiveuser.lst |  wget -q  --base=http://tieba.baidu.com -i - -O - | grep -Po "<div class="s_post">.*?<font class="p_green p_date">$(date --rfc-3339='date').*?</font>" |  iconv --from-code=latin1 --to-code=utf-8 | sed s/'^.*<a.*href="(.*)" class.*>(.*)</a>.*<div.*>(.*)</div>.*<font.*>(.*)</font>.*<font.*>.*([-0-9: ]{16})</font>.*$'/'1	2	3	4	5'/g
  • 相关阅读:
    Qt 交换Layout中的QWidget控件位置
    霍夫变换(Hough)
    图像傅里叶变换
    通俗讲解:图像傅里叶变换
    傅里叶分析之掐死教程(完整版)
    一幅图弄清DFT与DTFT,DFS的关系
    Qt 实现简单的TCP通信
    Qt 基于TCP的Socket编程
    Socket原理讲解
    科研相机选择:sCMOS还是CCD?
  • 原文地址:https://www.cnblogs.com/diylab/p/4228632.html
Copyright © 2011-2022 走看看