无登录爬取糗事百科段子
第一步:获取页面源码
(1)先确定我们要爬取的页面的url,然后通过页面的开发者工具查看需要发送的headers信息。这里,糗事百科需要我们添加User-Agent这个头文件信息,不然建立连接会失败的。
(2)通过urllib2的Request(url, data, headers)函数生成一个请求包。data和headers都是可选的。这里不需要传递data但是要传递headers,必须在传递实参时写明headers = XXX,不然编译器不知道你传的是哪个数据的实参。
(3)通过urllib2的urlopen(req)函数来发送请求包并建立连接,函数返回一个响应。需要注意的是,可能会出现连接失败的情况,所以可以使用异常处理机制try-except来捕获异常,输出异常信息,比在编译时出现一大串信息要好。
(4)使用返回的响应对象的read()方法读取页面信息,通过decode(‘utf-8’)函数使页面信息解码成utf-8的数据,方便之后的处理。
重点:
①请求的data和headers
②异常处理
③信息读取和解码
第二步:提取所需信息
(1)由于上一步获取的页面的源代码,我们需要通过正则表达式来提取我们需要的信息,如发布人,被赞数以及段子文本。这里,我们必须仔细查看页面的源代码,看看我们的信息在哪里,然后使用正则表达式来匹配。使用re模块的compile函数生产字符模式pattern。这个pattern在所有的re模块函数中都会用到。
(2)将pattern作为实参传递给findall函数,找到符合要求的字符串。在这里就是要匹配到所有段子所在的部分,以列表的形式作为findall的返回值返回,列表的元素为一个匹配成功的字符串。
(3)使用循环逐个处理每一个成功匹配的字符串。
(4)根据应用把所需的信息存储起来。
重点:
①查看源代码的布局。
②最常用的正则表达式部分是
.∗?
,这是非贪婪模式的最长匹配,也就是说一旦匹配到
?
后面的字符就立刻停止匹配。加上括号
③提取了信息后,可以根据应用需要进行字符串上的修改。因为提取的信息可能还包含诸如
<br/>
<script type="math/tex" id="MathJax-Element-945">
</script>等html符号,还有空格,空行,所以要获取干净的文本必须进行处理。
第三步:构建程序逻辑
(1)这一步比较工程化,只需要把上述步骤封装好,确定好程序的逻辑,就可以自顶向下地编写代码了。可以用面向对象的方法来构建一个爬虫类,提高代码的重用性。
重点:
①要注意python面向对象的特点,例如类方法中的参数第一个都是指向实例的参数,不能漏。
②类的成员,不管是数据成员还是成员函数,都需要通过self.XXX的方式调用,而且不要跟自己声明的局部变量混淆了。
③如果在输入input函数中显示中文要是用一下方式unicode(‘XXX’, ‘utf-8’).encode(‘gbk’)。
程序部分:自己实现的程序
下面是我实现的根据页数爬取糗事百科中的段子,并显示出来的程序。
__author__ = 'HJX'
# _*_ coding: utf-8 _*_
import re
import urllib
import urllib2
import thread
import time
class QSBK2:
'糗事百科爬虫2'
def __init__(self):
self.pageIndex = 1;
self.url = 'https://www.qiushibaike.com/hot/page/'+str(self.pageIndex);
self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
self.headers = {'User-Agent' : self.user_agent}
self.stories = []
def getPageCode(self):
try:
req = urllib2.Request(self.url, headers = self.headers)
res = urllib2.urlopen(req)
pageCode = res.read().decode('utf-8')
return pageCode
except urllib2.URLError, e:
if hasattr(e, 'reason'):
print u'获取源码失败,原因是:', e.reason
return None
def getStories(self):
stories = []
pageCode = self.getPageCode()
if not pageCode:
print u'获取当前页面段子失败!'
return None
pattern = re.compile('<div.*?author clearfix">.*?<h2>(.*?)</h2>.*?content">.*?span>(.*?)</span>.*?number">(.*?)</i>', re.S)
items = re.findall(pattern, pageCode)
for item in items:
publisher = item[0].strip()
br = re.compile('<br/>')
text = re.sub(br, '\n', item[1])
vote = item[2].strip()
stories.append([publisher, text, vote])
return stories
def showStories(self):
if len(self.stories) == 0:
print u'当前页数没有段子!'
else:
for story in self.stories:
publisher = story[0]
text = story[1]
vote = story[2]
print u'发布人:%s\t\t被赞数:%s\n%s\n' % (publisher, vote, text)
def start(self):
print u'-----糗事百科爬虫阅读器,根据页数看段子-----'
while 1:
self.pageIndex = input(unicode('请输入您要看的页数,输入0退出程序:', 'utf-8').encode('gbk'));
if self.pageIndex == 0:
print u'程序已退出!'
break
self.stories = self.getStories()
self.showStories();
spider = QSBK2()
spider.start()