本帖最后由 二哲科技 于 2021-6-5 08:00 编辑

1.介绍
这个工具主要是为了给大家提供便利,主要的功能是可以检测面包板一篇帖子的回复人数,重复回复的算一个人,同时还可以过滤掉某个人的回复(不计算这个账户的回复),其实这个工具也是比较简单的,会爬虫的同学基本都能做,这里也是为了复习一下爬虫的过程,最后会把源码放出来,温故而知新嘛~
2.界面设计
为了方便,我还是通过Python自带的【tkinter】库来做界面的设计,根据设计的需要,创建了几个空间,然后设置布局,代码如下:
translateWindow = tk.Tk()
  • framUrl = tk.Frame(translateWindow)    # 链接布局
  • urlSourceText = tk.Text(framUrl, height=1, width=50) # 链接输入
  • urlSourceLable = tk.Label(framUrl, text="链接:")    # 链接提示
  • framOther = tk.Frame(translateWindow)    # 子布局
  • filterLable = tk.Label(framOther, text="过滤账号:")    # 过滤提示
  • filterText = tk.Text(framOther, height=1, width=20)    # 过滤器
  • queryString = tk.StringVar()        # 用于label显示
  • queryString.set("他人回帖:00")      # 设置显示内容
  • queryResultLable = tk.Label(framOther, textvariable=queryString, width=20) # 结果
  • queryButton = tk.Button(framOther, text="查询", command=query_opt) # 查询按钮
  • def windowInit():
  •     translateWindow.title("二哲面板版社区回复量统计工具V1.0")
  •     framUrl.pack()
  •     urlSourceText.pack(side="right")
  •     urlSourceLable.pack(side="left")
  •     framOther.pack()
  •     filterLable.pack(side="left")
  •     filterText.pack(side="left")
  •     queryButton.pack(side="left")
  •     queryResultLable.pack(side="right")
  •     pass
  • 复制代码
    最终做出来的界面如下图所示,非常的简洁。
    1.jpg

    图1

    3.逻辑设计
    界面有了之后就需要开始设计逻辑了,这里大概说一下逻辑,就不画流程图了。
    首先,需要打开输入的网页,然后获取网页里面的内容,先获取回复总量,这样就可以知道有几页,然后获取一页内容中的回复者的用户名,加入到列表中,列表中有该用户名就不再添加,最后将列表中的数量导出,就知道回复量有多少了,如果有过滤用户名,在加入列表的时候判断一下就行了。
    1)获取网页信息
    首先不能直接用【urllib】库直接访问网页,这样网页会检测到为Python浏览器,如果有反爬虫机制,那么就会访问不成功,所以需要定义一个用户代理,输入相应的浏览器头部信息,然后再去获取网页的内容,代码如下:
    # 得到一个指定URL的网页内容
  • def askURL(url):
  •     #用户代理,为了伪装是一个正常的浏览器访问服务器,可以接收什么样的文件
  •     #模拟浏览器的头部信息,向豆瓣服务器发送消息
  •     head = {
  •         "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36",
  •         "Cookie":r'bid=yMpjnJKYK-A; __yadk_uid=24f4GNqWPZXeLu89FnNW6GDNAKy7bS4R; __gads=ID=a4c039c33134b66a-22500975f3c5000b:T=1612522231:RT=1612522231:S=ALNI_MYDVJRHIwRllWY32HeGC00MpHzQBw; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1612587979%2C%22https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DTLXTKAufK13I4BAdr8sadqFQL2IdrIxUZxAqFg1qbYuywukAM01wWmResSJUg8TE%26wd%3D%26eqid%3Dcc90a90d0016555d00000002601e23ca%22%5D; _pk_ses.100001.4cf6=*; ap_v=0,6.0; __utma=30149280.331411626.1612521875.1612521875.1612587979.2; __utmc=30149280; __utmz=30149280.1612587979.2.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmz=223695111.1612587979.2.2.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmc=223695111; __utmb=223695111.0.10.1612587979; __utma=223695111.1383473178.1612521875.1612521875.1612587979.2; dbcl2="232217138:S6fowfmyqr8"; ck=T_i5; push_noty_num=0; push_doumail_num=0; __utmt=1; __utmv=30149280.23221; __utmb=30149280.6.10.1612587979; _pk_id.100001.4cf6=22db73d9ea7d3d75.1612521875.2.1612588894.1612522237.'
  •         }
  •     request = urllib.request.Request(url, headers=head)
  •     html = ""
  •     try:
  •         response = urllib.request.urlopen(request)
  •         html = response.read().decode("utf-8")
  •         # print(html)
  •     except urllib.error.URLError as e:
  •         if hasattr(e, "eode"):
  •             print(e.code)
  •         if hasattr(e, "reason"):
  •             print(e.reason)
  •             pass
  •     return html
  • 复制代码
    获取完成网页内容之后,需要先获取用户的回复量,这样才能根据回复量来判断需要检测多少页,首先通过【bs4】库对网页进行解析,获取到【div】标签中【class_="read-reply hidden-xs"】的地方,然后用正则表达式获取回复量,代码如下:
    findRecNum = re.compile(r'<span>回复:(.*?)</span>')   # 获取回复数量
  • if recNum == 999:   # 是否是第一次进入,为了获取回复量
  •             recNum = int(re.findall(findRecNum, str(soup.find_all("div", class_="read-reply hidden-xs")[0]))[0]) # 获取回复数量
  •             pass
  • 复制代码
    回复量有了,那就需要有切换页面的逻辑了,这里是直接进入不同的页面,根据测试,知道了网址【https://mbb.eet-china.com/forum/topic/90290_1_1.html】中的加粗部分为对应得页码,这样通过修改这个数值就可以访问指定的网页了,代码如下:
    findPageNum = re.compile(r'_._')   # 检测到第几页
  • recHtmlTemp = findPageNum.sub("_" + str(pageNum) + "_", recUrl) # 先定位到第一页
  •         # print("recHtmlTemp" + str(pageNum))
  •         pageNum = pageNum + 1   # 第二页,不一定会去
  • 复制代码
    可以获取不同的页,最后一步就是获取每一页里面的用户回复了,由于一条回复里面有很多显示用户名的地方,我挑选了比较合适的一个字段来进行爬取,获取到【div】标签中【class_="thetitle-xs visible-xs visible-sm"】的地方,然后获取用户名,对每一页都进行如此操作,然后将用户名存储到列表中,最后输出列表长度即可,代码如下:
    findName = re.compile(r'<a class="username-xs" href="(.*?)" target="_blank">(.*?)</a>')   # 获取回复的人
  • for item in soup.find_all("div", class_="thetitle-xs visible-xs visible-sm"):   # 获取回复者
  •             # print(item)
  •             item = str(item)    #把数据全部变成字符串
  •             recName = re.findall(findName, item)[0] # 获取链接和名字
  •             # print(recName[1])   #输出获取到的用户
  •             if recName[1] not in recNameArray:  # 判断是否在列表中
  •                 if filterName != recName[1]:    # 判断是否要过滤名字
  •                     recNameArray.append(recName[1]) #添加到列表中
  •                     recNameCnt = recNameCnt + 1 # 回复人数加一
  •                     # print(recNameCnt)
  •                 pass
  •             pass
  •         pass
  • 复制代码
    其他细节就不过多的讲解了,后面会给出源码,感兴趣的同学可以自行下载查看。
    最终展现出来的效果如下图所示。
    2.jpg

    图2

    4.总结
    其实整体设计不难,但是由于挺久没接触了,所以稍微生疏了一下,花了一个晚上时间才写出来的,测试了一下效果还是不错的,希望这个小工具能帮助到大家~
    源码:
    游客,如果您要查看本帖隐藏内容请回复