基于正则表达式(python)对东方财富网上证指数吧爬虫实例

来源:互联网 发布:ubuntu搭建博客 编辑:程序博客网 时间:2024/05/16 18:03

这一周没有写博客,倒腾了好几天gitlab,白天一直在写爬虫,遇到了很多问题,一一解决了

这个爬虫目的是从东方财富网的 上证指数吧 爬取一天的所有发帖
http://guba.eastmoney.com/list,szzs,f.html

具体实现步骤如下:

1.分析网站首页

这里写图片描述

1.首页上有一个按照发帖时间排序我选择的target_urls是根据这个排序产生的网址集2.对于分页的处理,我是进行的迭代确定的每夜的网址url3.判断退出循环的标志  原本希望通过获得右下角的那个总页数,但是那个数据是通过js加载出来的,而这个爬虫是通过下载静态html然后解析数据,所以是找不到那个总页数所在的节点的.所以最终设置循环的上限并没有动态生成而是人工指定  (~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~待改进一)

代码片段:

def add_new_url(self,i):                                self.target_urls.add('http://guba.eastmoney.com/list,szzs,f_%d.html'%i)     return        def add_new_urls(self,n):     for i in range(1,n+1):#range使用        self.add_new_url(i)     return

2.分析帖子url

1.'/news  ........ html'是帖子的url的后缀相同部分2.因为我们将要访问url来下载评论,所以要把整个url拼接好 使用urlparse模块的urljoin方法
 def parse(self,page_url):       self.new_comment_urls=set()       urls2=set()         html_cont=urllib2.urlopen(page_url).read()       new_comment_urls=re.findall('/news\S+html',html_cont)       for comment_url in new_comment_urls :            fu_url=urlparse.urljoin(page_url,comment_url)            urls2.add(fu_url)       return urls2

3.下载评论内容

  1.我们下载好了发帖的html全部内容后,要提取出具体的评论部分  2.注意正则表达式的使用,因为具体的html里评论部分前后有好多换行,我在这里憋了好长时间,因为正则表达'.+'在一般的语言中可以匹配到'\n'python的re模块中只有启用dotall模式,'.'才可以匹配换行符,~~~~~~~~~~~~~~~~~~~~~~~~~~~~~恶心了我一下午  [查看html代码](view-source:http://guba.eastmoney.com/news,szzs,398272537.html)
 html_cont1=self.open_url(url)        com_cont=re.compile(r'stockcodec.+zwconbtns clearfix',re.DOTALL)        print com_cont        cont=com_cont.search(html_cont1).group()        return cont

4.输出

    1.我选择的是每一个帖子的内容都存到一个txt里,所以需要迭代生成文件名(而不是在w+的过程中迭代,这样貌似成功不了)    2.这个地方我没有搞太懂,瞎试出来的(编码部分).python的unicode utf8 ascii我还没有弄清楚~~~~~~~~~~~~待学习
def out_txt(self,conts):        i=0        for cont in conts:            i=i+1            name= "cont%d.txt"%i            f=codecs.open(name,'w+','utf-8')            f.write(cont.decode('utf-8'))            f.close()        return 

如上是代码的基础部分,是后者,主函数关于循环情况以及几个特殊情况的处理,我到现在也处理的不太好,我会介绍我的处理方式,但是感觉不太好,但是确实想了很久.

class spidermain(object):    def __init__(self):        self.target_urls=target_url_manager()        self.parser=find_comment()        self.downloader=htmldownloader()        self.outputer=output_txt()    def craw(self,sumpage):        conts=set()        error_time=0        true_time=0        time_start=time.strftime("%Y-%m-%d",time.localtime(time.time()))        self.target_urls.add_new_urls(sumpage)        while self.target_urls.has_target_url():             new_url=self.target_urls.get_new_url()             urls2=self.parser.parse(new_url)             for url in urls2:                if self.downloader.find_time(url) ==  time_start :                   cont=self.downloader.download(url)                   print  cont                   conts.add(cont)                   true_time=true_time+1                   error_time=0                else:                   error_time=error_time+1                   if error_time >= 10 :                       break                print '%s has a sum of %d comments'%(time_start ,true_time)                self.outputer.out_txt(conts)                     returnif __name__=='__main__':    sumpage=1    obj_spider=spidermain()    obj_spider.craw(sumpage)

我设置的总页数是1,爬一页试试对不对,毕竟两万多页,几十万个帖子,我一个线程不知道要弄到哪年,所以先设置一页试试,一页也是有百十来个帖子的.
1.大循环是当目标url集还有目标url时执行.这部分我用了两个一个新集,一个旧集,分别用于存储未爬取的和已经爬取过的

class target_url_manager (object):     def __init__(self):        self.target_urls=set()         self.old_urls=set()     def add_new_url(self,i):         self.target_urls.add('http://guba.eastmoney.com/list,szzs,f_%d.html'%i)        return    def add_new_urls(self,n):        for i in range(1,n+1):#range使用            self.add_new_url(i)        return    def has_target_url(self):         return len(self.target_urls)!=0    def get_new_url(self):        new_url = self.target_urls.pop()#两个队列        self.old_urls.add(new_url)        return new_url

使用了pop和add方法

2.我设置了一个系统时间变量(年月日)然后去获取发帖的时间所以就可以只爬取一天的帖子.在我分析者一天一天数据的url时发现和他们在一起的那个发帖时间也是js加载出来,不能获取,但是又发现进入url后里边的时间是html里有的,所以我选择先进入帖子url再获取这个时间.

def find_time(self,url):        html_cont2=self.open_url(url)        tar_time=re.search('\d\d\d\d-\d\d-\d\d',html_cont2).group()         return tar_time 

3.我在浏览整体顺序时发现,这个网站的按照发帖时间排序并不严格,偶尔会出现一两个不是目标时间的帖子出现在大体都是一天的整个页面中
这里写图片描述
如图就是有几个穿插的时间不是五月二十一号的贴
所以我设置了两个变量

error_time=0true_time=0

但是到一天发帖最后涉及到更换日期(我这里没有涉及)的时候,该怎么判断呢
我没有想到很好的办法,但是发现错误连续出现的次数都在五个以内,所以我设置错误的连续次数为五,当连续错误超过五个,就判定已经到了下一天的帖子.

        for url in urls2:                if self.downloader.find_time(url) ==  time_start :                   cont=self.downloader.download(url)                   print  cont                   conts.add(cont)                   true_time=true_time+1                   error_time=0                else:                   error_time=error_time+1                   if error_time >=5 :                       break

期中还设置了一个归零,在错误不连续的时候不能累加.

大致的思路就是这样,太多槽点,好多不合理,有待改进的地方,接下来的学习小点如下:

1.这两种初始集合,第一种不能作为函数的返回值,第二种可以,具体的原因怎么表达
 self.new_comment_urls=set() urls2=set()
2.各种编码方式的理解和认识3.关于爬取js页面的方法4.主函数的判退怎样更优5.切换爬取的目标日期怎么切换6.基于正则表达式的最终发帖内容有一些无关紧要的字符串,使用beautifulsoup改进7.dry原则,如何减少重复代码,类和方法怎样安排最合理,调用起来是否方便8.多线程改进.提高爬取效率,如何设计线程

作为一个小菜鸟成功的写出来这一段程序很开心,但是回头却发现,我发现的问题远比我已经解决的问题多,越学越宽,越学越宽,坚持把

~~还望不要喷的太狠,的确是很烂
源码已上传github
https://github.com/CCyutaotao/gubaspider

0 0
原创粉丝点击