之前有个网友在贴吧做营销,那个贴吧每天都会产生100多的邮箱号,有网友就让我写个软件,别人发帖让用户留邮箱,自己却用脚本把用户留的邮箱全部采集下来,软件已经经历了两个版本,有时间再改进一下。
软件界面:
下面代码是程序主入口,主要写了软件界面和函数调用,界面是tkinter写的,因为我觉得这个比较简单当时就学这个了,就是界面比较丑,一些比较简单的软件足够用了,代码比较乱,之前一直用面向过程写方法函数,现在慢慢改习惯用面向对象了,软件的每调用一些耗时的函数,必须用上
threading创建线程,开创新的线程就不会影响软件界面,不然软件会卡死。
from tieba_pc import * # from tkinter import W,E,N,S,Button,Label,Text,Tk,Entry from tkinter import INSERT import tkinter.messagebox from threading import Thread # from requests import get from tkinter import * import webbrowser #import threading def qk(): # 清空按钮 text1.delete(1.0, END) text2.delete(1.0, END) def tieba_cj(): # 读输入的域名 text_content = (text1.get("0.0", "end").replace(" ", "")).split(" ") text_content.pop() # 列表最后一个元素是空删除它 if text_content[0] == '': tkinter.messagebox.showinfo(title='提示', message='麻烦把贴吧名填一下再提交!') else: rad = r.get() # 控制采集时间段 pn = e.get() # 贴吧翻页 yx = tm.get() # 运行状态控制 xcx = xc.get() # 下次控制 bcwj = wj.get() x=0 # 控制贴吧数 text2.insert(END, "可以最小化软件去忙其他事了!" + ' ') for ming in text_content: # 这里对输入的贴吧循环采集 # 单线程 if xcx == 1 : tieba_caiji(ming, int(rad), text2, int(pn), int(yx),int(bcwj)) # 多线程 elif xcx == 2 : t = Thread(target=tieba_caiji, args=(ming, int(rad), text2, int(pn), int(yx),int(bcwj),)) t.start() t.join() x = x + 1 if x == 5 : break time.sleep(3) # 全部采集完成 # 版本更新函数 def bbgx(): pass # 采集函数 def th1(): t1 = Thread(target=tieba_cj) t1.start() # 版本更新函数 def th2(): t1 = Thread(target=bbgx) t1.start() # 说明提示 def sm(): tkinter.messagebox.showinfo(title='说明', message='欢迎使用本软件,软件仅用于交流使用! 软件用于贴吧邮箱采集,可以选择多个贴吧监控邮箱回复采集,可以选择回复时间进行采集,可以24小时不间断采集,多线程采集,采集的邮箱保存到文本文件,可以轻松复制邮件群发!') ###########------公共变量定义------------######### banben = 1.1 ###########----------------- UI 界面乱写开始 -------------------------######### root=Tk() #生成root主窗口 root.title('贴吧邮箱采集器') root.resizable(0,0) root.geometry('840x680') # 两个布局控件 frm1 = tkinter.Frame(root,height=100,width=400,).grid(row=0,column=0,sticky=N+W) frm2 = tkinter.Frame(root,height=280,width=200,).grid(row=7,column=0,padx=15,sticky=N+W) frm3 = tkinter.Frame(root,height=280,width=260,).grid(row=7,column=1,padx=15,sticky=N+W) # background='#FFFFFF'height=380,width=260, # 按钮控件 Button(frm1,text='开始采集',height=2,width=20,fg='red',font=10,command=th1).grid(row=0,column=0,columnspan=1,pady=0,padx=15,) Button(frm1,text='清空',height=0,width=8,fg='red',font=10,command=qk).grid(row=0,column=1,pady=0,columnspan=1,padx=10,sticky=E) Button(frm1,text='说明',height=0,width=8,fg='red',font=10,command=sm).grid(row=0,column=2,pady=0,padx=10,sticky=E) # 单选标签 r=tkinter.IntVar()#给单选框添加variable,用于显示value值 r.set(1) radio1=tkinter.Radiobutton(frm1,text="采集当天",value=1,variable=r).grid(row=1,column=0,pady=10) radio2=tkinter.Radiobutton(frm1,text="不限制时间",value=10,variable=r).grid(row=1,column=1,pady=10) radio3=tkinter.Radiobutton(frm1,text="采集前七天",value=7,variable=r).grid(row=1,columnspan=2,pady=10) Label(frm1, text="运行状态:", height=0,).grid(row=2, column=0,columnspan=1,sticky=W+E+N+S) # columnspan=2, # 单选标签 tm=tkinter.IntVar()#给单选框添加variable,用于显示value值 tm.set(1) tmadio1=tkinter.Radiobutton(frm1,text="运行一次",value=1,variable=tm).grid(row=2,column=1,pady=10) tmadio2=tkinter.Radiobutton(frm1,text="每隔1小时运行一次",value=2,variable=tm).grid(row=2,columnspan=2,pady=10) Label(frm1, text="线程选择:", height=0,).grid(row=3, column=0,columnspan=1,sticky=W+E+N+S) # columnspan=2, # 单选标签 xc=tkinter.IntVar()#给单选框添加variable,用于显示value值 xc.set(1) xcadio1=tkinter.Radiobutton(frm1,text="单线程采集",value=1,variable=xc).grid(row=3,column=1,pady=10) xcadio2=tkinter.Radiobutton(frm1,text="多线程采集",value=2,variable=xc).grid(row=3,columnspan=2,pady=10) # 文本加文本框 Label(frm1, text="采集贴吧前多少页(最好10以内):", height=0,).grid(row=4, column=0,columnspan=1,sticky=W+E+N+S) e = StringVar() Entry(frm1, bd =0,textvariable=e).grid(row=4,column=1,pady=10) e.set('1') Label(frm1, text="是否存入数据文件:", height=0,).grid(row=5, column=0,columnspan=1,sticky=W+E+N+S) # columnspan=2, # 单选标签 wj=tkinter.IntVar()#给单选框添加variable,用于显示value值 wj.set(1) wjadio1=tkinter.Radiobutton(frm1,text="否",value=1,variable=wj).grid(row=5,column=1,pady=10) wjadio2=tkinter.Radiobutton(frm1,text="是",value=2,variable=wj).grid(row=5,columnspan=2,pady=10) # 文本标签 Label(frm1, text="输入贴吧名不要带吧、一行一个贴吧,一次最多采集5个", height=0,).grid(row=6, column=0,sticky=W+E+N+S,padx=25,pady=1) # ,columnspan=1 Label(frm1, text="运行日志输出区", height=0,).grid(row=6, column=1,columnspan=2,sticky=W+E+N+S,pady=1) # 多行输入框 text1 = Text(frm2,width=25,height=14,font=10) text2 = Text(frm3,width=32,height=14,font=10) # 布局输入框,这里单独拿出来放,不然出问题 text1.grid(row=7,column=0,padx=5,pady=1) text2.grid(row=7,column=1,padx=5,pady=1) Label(frm1, text="版本:%s - 大铭 "%banben, height=0,).grid(row=8, column=2) # 检查更新函数 th2() root.mainloop() #进入消息循环(必需组件)
爬虫函数,被软件界面调用的函数,包括爬取和将数据写入文件。
from main_def import * import requests,re import datetime,time from tkinter import END headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36"} # 单个帖子爬虫 def tz_cj(url,time_xz): #########-----------分割线--------------############################# #########------------开始帖子邮箱采集-------------#################### # 选择采集时间控制变量,1 为当天,7 为前七天,10 为不限制时间 #time_xz = 7 # 获取当前时间 time1 = datetime.datetime.now().strftime('%Y-%m-%d') # 邮箱存储列表 yx_list = [] # 循环控制变量 pn = 1 while True: t_url = url + "?pn=" + str(pn) t_re_html = requests.get(t_url, headers=headers).text # 获取页数 red = re.findall('<span class="red">(.*?)</span>', t_re_html)[0] # 正则匹配提取每一个楼层 t_nr_1 = re.findall('<div class="l_post j_l_post l_post_bright "(.*?)</div><br>', t_re_html, re.S) t_nr_2 = re.findall('<div class="d_post_content_main ">(.*?)</span></div><ul class="p_props_tail props_appraise_wrap"></ul>', t_re_html, re.S) t_nr = t_nr_1 + t_nr_2 # 循环遍历页面所有楼层 for re_lc in t_nr: # 这里做一个错误跳转,楼层没有邮箱则跳过 try: # 提取楼层发布时间 times = re.search(r"(d{4}-d{1,2}-d{1,2})", re_lc) tims = (times.group(0)) # 提取楼层邮箱 pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,5}' items = re.findall(pattern, re_lc)[0] # 判断采集当天 if time_xz == 1: # 只爬取当天邮箱 if time1 == tims: yx_list.append(items) # 判断采集前七天 elif time_xz == 7: time7 = datetime.datetime.today().date() - datetime.timedelta(days=8) if str(tims) > str(time7): yx_list.append(items) # 判断采集不限制时间 elif time_xz == 10: yx_list.append(items) except: continue # 加页数 pn = pn + 1 # 判断翻页完成跳出循环 if pn - 1 == int(red): break time.sleep(0.5) return yx_list # 返回采集到的邮箱 # 文件写入函数 def text_save(filename,data,ts,text2): #filename为写入文件的路径,data为要写入数据列表. datas = list(set(data)) # 去除重复邮箱 times = datetime.datetime.now().strftime('%Y-%m-%d-%H') file = open(times + "-" + filename + "吧邮箱采集文件.txt", 'a') for i in range(len(datas)): s = str(datas[i]).replace('[', '').replace(']', '') # 去除[],这两行按数据不同,可以选择 s = s.replace("'", '').replace(',', '') + ' ' # 去除单引号,逗号,每行末尾追加换行符 file.write(s) file.close() text2.insert(END, "第%d个帖邮箱采集成功保存文件!"%ts + ' ') wjm = times + "-" + filename + "吧邮箱采集文件.txt" return wjm # 把文件名返回 # 页面入口函数 def tieba_caiji(kw,time_xz,text2,pn,yx,bcwj): # kw传贴吧名,time_xz采集控制当天 text2传一个句柄 ,yx传运行状态 pn 传贴吧翻页 while True: for ye in range(int(pn)): # 这个循环是循环贴吧翻页 pn = ye * 50 url = "https://tieba.baidu.com/f?kw=%s&ie=utf-8&pn=%d" % (kw, pn) # 爬贴吧第一页的所有帖子 html = requests.get(url, headers=headers).text re_html = re.findall('<div class="threadlist_title pull_left j_th_tit ">(.*?)</div>', html, re.S) ts = 1 # 统计帖数 for i in re_html: href = re.findall('href="(.*?)"', i, re.S)[0] t_url = "https://tieba.baidu.com" + href yx_list = tz_cj(t_url, time_xz) wjm = text_save(kw, yx_list, ts, text2) time.sleep(3) ts = ts + 1 text2.insert(END, "%s吧第%d页采集完成!" % (kw,ye+1) + ' ') text2.insert(END, "%s吧采集完成!" % (kw) + ' ') # 保存入今日文件 if bcwj == 2 : wenjian_xr(wjm) #如果为 2 则等待1小时 运行 if yx == 2 : time.sleep(3600) # 翻页完成,退出软件 else: break
这个函数有点啰嗦了,将每次采集的数据写入一个总TXT文件。
import datetime import os # 将当前采集到的文件写入今日文件 def wenjian_xr(times): # 传入当前采集到的文件名 time3 = datetime.datetime.now().strftime('%Y-%m-%d') # 判断是否存在数据目录,没有则创建 wenjian = os.path.exists('./dmzy5') if wenjian == False: os.mkdir('dmzy5') #print("创建成功") file = open(times) lines = file.readlines() list2 = ([' '.join([i.strip() for i in price.strip().split(' ')]) for price in lines]) # 读取传入的文件,变成列表完成 file.close() # 将采集到的文件写入今日数据文件 file_2 = open("./dmzy5/" + time3 + "- 邮箱采集文件.txt", 'a') for i in range(len(list2)): s = str(list2[i]).replace('[', '').replace(']', '') # 去除[],这两行按数据不同,可以选择 s = s.replace("'", '').replace(',', '') + ' ' # 去除单引号,逗号,每行末尾追加换行符 file_2.write(s) file_2.close() # 读取今日数据文件,变成列表 file_3 = open("./dmzy5/" + time3 + "- 邮箱采集文件.txt") lines2 = file_3.readlines() lines2 = ([' '.join([i.strip() for i in price.strip().split(' ')]) for price in lines2]) file_3.close() # 今日数据文件去重 lists = [] # 最后写入的列表 for i in lines2: if i not in lists: lists.append(i) # 把原文件删除,重新创建写入 os.remove("./dmzy5/" + time3 + "- 邮箱采集文件.txt") file_4 = open("./dmzy5/" + time3 + "- 邮箱采集文件.txt", 'a') for i in range(len(lists)): s = str(lists[i]).replace('[', '').replace(']', '') # 去除[],这两行按数据不同,可以选择 s = s.replace("'", '').replace(',', '') + ' ' # 去除单引号,逗号,每行末尾追加换行符 file_4.write(s) file_4.close()