python爬虫之百度贴吧

第一步:通过urllib2,Request命令和urlopen命令爬取贴吧网页源码,并通过这则表达式,选取自己想要的数据

在这里需要注意几个地方

1.编码问题,这里对中文编码不再进行过多阐述。

网页源码是utf-8,我在编写程序前# -*- coding:utf-8 -*-,那么显示在网页上,我只需要在urllib2.urlopen(res).read()后面加上.decode('utf-8')  即可

如果出现鏂囦欢鍚嶏細 这样的中文乱码,实际上只需要在print后加上u""就可以了

2.当抓取完页面,无论在输出是写入print或retrun,都没有关系,但在后面的正则表达式操作时需要注意要使用return返回

3.编码实在想不清楚,可以在项目开头写入

import sys
reload(sys)
sys.setdefaultencoding('utf8')

代码如下

 

 1 #coding=utf-8  
 2 
 3 import urllib2  
 4 import urllib  
 5 import re  
 6 import sys  
 7 reload(sys)  
 8 sys.setdefaultencoding('utf8')   
 9 
10 class BDTB:  
11     def __init__(self,baseUrl,seeLZ):  
12         self.baseUrl=baseUrl  
13         self.seeLZ='?see_lz='+str(seeLZ)  
14         
15   
16     def getTitle(self):  
17         html=self.getPage(1)  
18         pattern=re.compile(r'<h3 class="core_title_txt.*?">(.*?)</h3>')  
19         title=re.search(pattern,html)  
20         if title:  
21             return title.group(1)  
22         else:  
23             return  None 
24        
25     def getPageNum(self):  
26         html=self.getPage(1)  
27         pattern=re.compile(r'<li class="l_reply_num.*?</span>.*?<span.*?>(.*?)</span>')  
28         nums=re.search(pattern,html)  
29         if nums:  
30             return nums.group(1)  
31         else:  
32             return None  
33     def getContent(self,html):  
34         pattern=re.compile(r'<div id="post_content.*?">(.*?)</div>')  
35         contents=re.findall(pattern,html)  
36         for item in items:
37             print item
38           
39     def getPage(self,pageNum):  
40         try:  
41             url=self.baseUrl+str(self.seeLZ)+'&pn='+str(pageNum)  
42             res=urllib2.Request(url)  
43             res.add_header('User-Agent','Mozilla 5.10')  
44             html=urllib2.urlopen(res).read().decode('utf-8')  
45             print html  
46         except urllib2.URLError,e:  
47             if hasattr(e,"reason"): #判断一个对象里面是否有name属性或者name方法,返回布尔  
48                 print u"错误",e.reason  
49                 return None     
50   
51 baseUrl='http://tieba.baidu.com/p/3138733512' 
52 
53 bdtb=BDTB(baseUrl,1)  
54 bdtb.getPage(1)

第二步:实现获取界面规划并写入文本中

这里需要注意几个地方

1.TypeError: getPageNum() takes exactly 1 argument (2 given)
getPageNum这个函数需要2个参数才可以,调用时只给了1个
所以我将def getPageNum(self):改为def getPageNum(self,page):其中page在执行语句page=self.getPage(1)

2.为甚要用self

self是类方法的一个位置参数,它就是类的实例对象自己,当实例调用方法时:
instance = X()
instance.f('a', 'b')
等同于:
X.f(instance, 'a', 'b')
第一个参数是实例自己。

3.TypeError: expected string or buffer

这里,我所遇到的问题就是在第一步中将return和print的使用弄混,导致出现这样参数传入错误的error,网上其他人的错误有的是因为网址些错误,导致传入的网址参数错误。我的修改很简单,将print修改成return,错误就消失了。

将html=urllib2.urlopen(res).read().decode('utf-8')
print html
改成html=urllib2.urlopen(res).read().decode('utf-8')
return html
就好了
为什么呢
return作用之一是返回计算的值
print是输出数据到控制端,额这说了我也不明白
直接上代码吧
x=1
y=2

def add(x,y):
z=x+y
print z
print add(x,y)

结果是 3
None
而x=1
y=2

def add(x,y):
z=x+y
return z
print add(x,y)
结果是 3
在交互模式下,return的结果会自动打印出来,而作为脚本单独运行时则需要print函数才能显示。
而为什么错误是传入的参数有问题呢,因为我们使用request获取该页的代码,用return的意思就是执行完这条语句之后不再执行语句,并返回所传的数据
而print是执行完这条语句后,在屏幕显示内容
我们之后需要进行获取标题内容正则表达式等操作,而我们若使用print,则相当于对空的内容进行操作,所以报错,说返回参数有错误

4.对于文本的理解

实际上就是使用writeline()方法,可以参考http://www.runoob.com/python/file-writelines.html

作用:向文件中写入一序列的字符串
这一序列字符串是由可以迭代对象产生
语法:file.writeline([str])
参数:str 要写入文件的字符串
返回值:这方法没有返回值

就我的理解就是用file = open(“tb.txt”,”w”)建立文本,txt格式,再将字符串写入str,使用writeline()方法写进文本,而file相当于一个全局变量

代码如下

  1 # -*- coding:utf-8 -*-
  2 import urllib2       
  3 import urllib       #urllib2
  4 import re          #正则表达式
  5 
  6 import sys
  7 reload(sys)
  8 sys.setdefaultencoding('utf-8')
  9 class Tool:
 10     removeImg = re.compile('<img .*?>',re.S) 
 11     removeAddr = re.compile('<a .*?>(.*?)</a>',re.S)  
 12     replaceLine = re.compile('<tr>|<div>|</div>|</p>',re.S)  
 13     replaceTD = re.compile('<td>',re.S)  
 14     replacePara = re.compile('<p .*?>',re.S)  
 15     replaceBR = re.compile('<br><br>|<br>',re.S)  
 16     removeExtraTag = re.compile('<.*?>',re.S)    
 17     
 18     def replace(self,x):
 19         x=re.sub(self.removeImg,"",x)
 20         x = re.sub(self.removeAddr, "", x)  
 21         x = re.sub(self.replaceLine, "\n", x)  
 22         x = re.sub(self.replaceTD, "\t", x)  
 23         x = re.sub(self.replacePara, "\n  ", x)  
 24         x = re.sub(self.replaceBR, "\n", x)  
 25         x = re.sub(self.removeExtraTag, "", x)         
 26 
 27         return x.strip()
 28 class BDTB:
 29     
 30     def __init__(self,baseUrl,see_lz):  #这一行什么意思
 31         self.baseUrl=baseUrl
 32         self.seelz='?see_lz='+str(see_lz)
 33         self.tool=Tool()
 34         self.floor=1#楼层标号,初始为1
 35         self.defaultTitle=u'百度贴吧'
 36         #是否写入分层的标记
 37         self.floorTag=floorTag
 38         self.file=None#全局file变量,文件写入操作对象
 39     #传入页码,获取该页帖子代码
 40     def getPage(self,pageNum):    #为甚么总有一个self
 41         try:
 42             #url是网页规范,这一行的意思是在前面定义的基地址下加上是否查看楼主的seelz+页码,而页码是通过
 43             
 44             url=self.baseUrl+str(self.seelz)+'&pn='+str(pageNum)  
 45             res=urllib2.Request(url)
 46             html=urllib2.urlopen(res).read().decode('utf-8')
 47             return html
 48         except urllib2.UrlError,e:#为什么这么写
 49             if hasattr(e,"reason"):#hasattr是什么意思
 50                 print u'错误',e.reason
 51                 return None
 52     
 53     
 54     #页码 
 55             
 56     def getPageNum(self,page):
 57         page=self.getPage(1)
 58         pattern=re.compile('<li class="l_reply_num.*?</span>.*?<span.*?>(.*?)</span>',re.S)
 59         result=re.search(pattern,page)
 60         if result:
 61             return result.group(1).strip()
 62         else:
 63             return None
 64         
 65     #标题
 66     def getTitle(self,page):
 67         page=self.getPage(1)
 68         pattern=re.compile('<h3 class="core_title_txt.*?">(.*?)</h3>',re.S)
 69         result=re.search(pattern,page)
 70         if result:
 71             return result.group(1).strip()
 72         else:
 73             return None
 74             
 75     
 76 
 77     #获取内容
 78     def getContent(self,page):
 79         pattern=re.compile('<div id="post_content_.*?">(.*?)</div>',re.S)
 80         items=re.findall(pattern,page)
 81         #for item in items:
 82         #    print item
 83         #print self.tool.replace(items[1])
 84         #floor=1
 85         contents=[]#将匹配的内容都放到数组里面
 86         for item in items: 
 87             #print floor,u"楼-------------------------------------------------\n"
 88             #print self.tool.replace(item)
 89             #floor +=1
 90             content="\n"+self.tool.replace(item)+"\n"
 91             contents.append(content.encode('utf-8'))
 92         return contents
 93     #以下都是将内容发送到文本里面的时候怎么操作
 94     def setFileTitle(self,title):#这是将标题获取,放到记事本里面
 95         if title is not None:#如果title不是None
 96             self.file=open(title+".txt","w+")#这一句什么意思
 97         else :
 98             self.file=open(self.defaultTitle+".txt","w+")
 99     #以下是将楼层写进去
100     def writeData(self,contents):
101         for item in contents:
102             if self.floorTag=='1':
103                 floorLine="\n"+str(self.floor)+u"-------------------------\n"
104                 self.file.write(floorLine)
105             self.file.write(item)
106             self.floor +=1
107     #交互界面
108     def start(self):
109         indexPage=self.getPage(1)#获取该页页码
110         pageNum=self.getPageNum(indexPage)#h获取一共有多少页
111         title=self.getTitle(indexPage)#获取该页码的标题
112         self.setFileTitle(title)
113         if pageNum==None:
114             print "URL已失效,请重试"
115             return #结束
116         try:
117             print u"该帖子共有"+str(pageNum)+''
118             for i in range(1,int(pageNum)+1):
119                 print u"正在写入第"+str(i)+"页数据"
120                 page=self.getPage(i)
121                 contents=self.getContent(page)
122                 self.writeData(contents)
123             #出现写入异常
124         except IOError,e:
125             print u"正在写入第"+str(i)+"页数据"
126         finally:
127             print u"写入任务完成"
128 print u"请写入帖子代号"
129 baseUrl='http://tieba.baidu.com/p/'+str(raw_input(u'http://tieba.baidu.com/p/'))
130 seelz=raw_input(u"是否获取楼主发言,是输入1,否输入0\n")
131 floorTag=raw_input(u"是否写入楼层信息,是输入1,否输入0\n")
132 
133 
134 
135 bdtb=BDTB(baseUrl, 1)#这里为什么为1
136 #bdtb.getContent(bdtb.getPage(1)) 
137 bdtb.start()

整个思路就是这样,参考崔庆才大大的博客,原网址如下

http://cuiqingcai.com/993.html

还有在实践过程中遇到的几个小问题

1.AttributeError: 'module' object has no attribute 'Requset'
拼写错误

2.这个是正则表达式发生错误,修改匹配正确源码正则表达式即可

2.这个是只获得第一页内容,如果要获得其他页内容可以修改items【a】a的值,如果要获得全部内容,则注释掉此句,上面被注释的就是

3.这里就是一页内容和所有内容的写法,所有内容用到了for   in循环

下一步可能是学习怎么将这个打包成exe应用

1.写好python工程
2.在setup.py上修改""中的文件,写上已经编好了的.py
3.cmd命令-->d:-->cd python ---->cd Script----->python setup.py py2exe
生成dist文件,将dist文件里面所有东西全部打包

不过有个小问题,同样的代码爬取帖子,有的帖子是中文乱码,有的却是正常的,且都是utf-8格式

然后,我把这个exe删了重新生成新的exe文件,结果乱码的帖生成txt显示正常

 

posted @ 2017-07-31 16:54  子不语怪力乱神  阅读(479)  评论(0编辑  收藏  举报