注意:原文章写于2016年12月
Python爬取目标
- 抓取糗事百科页面中的热门段子(包括作者和内容)
- 过滤带有图片的段子内容(Pycharm控制台无法输出图片)
- 使用Python面向对象对功能进行封装,并在控制台实现,敲击一次回车键显示一个段子作者和内容的功能。
功能实现
确定页面的HTML结构:确定需要抓取的页面为:http://www.qiushibaike.com/hot/,并在浏览器中使用F12功能,确定该网页的HTML结构,这里可以发现,需要抓取的内容的结构如下:
可知:
- 需要的所有段子信息均存放在id=”content left”的div中
- 相应的每一个段子的信息均在class=”article block untagged mb15″的div中
- 段子的标题存放在<h2>标签内
- 段子的内容存放在class=”content”的<div>中
编写功能代码
这里参考的资料链接为:Python爬虫实战(1):爬取糗事百科段子,但在此资料中,使用的是正则表达式的匹配的方式来抓取需要的HTML页面中的内容,这里使用BeautifulSoup更为方便简洁。而且由于糗事百科页面的改变,参考资料的原始正则表达式的匹配已经无法使用。
代码如下:
# -*- coding: UTF-8 -*-
import urllib
import urllib2
import re
from bs4 import BeautifulSoup
# 获取发布人,发布日期,段子内容,以及点赞的个数
page = 1
url = 'http://www.qiushibaike.com/hot/page/' + str(page)
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = {'User-Agent' : user_agent}
try:
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
# print response.read()
content = response.read().decode('utf-8')
# pattern = re.compile('<div.*?class="author.*?>.*?<a.*?</a>.*?<a.*?>(.*?)</a>.*?<div.*?class'+
# '="content".*?title="(.*?)">(.*?)</div>(.*?)<div class="stats.*?class="number">(.*?)</i>',re.S)
# items = re.findall(pattern, content)
object_bs = BeautifulSoup(content, "html.parser")
# 第一次编写的代码
# body = bs.body
# datadiv = body.find('div', {'id':'content-left'})
# dataList = datadiv.find_all('div', {'class':'article block untagged mb15'})
# for data in dataList:
# author = data.find('h2')
# contentdiv = data.find('div', {'class':'content'})
# content = contentdiv.find('span')
# stats = data.find('div', {'class':'stats'})
# number = stats.find('i', {'class':'number'})
# print author.string
# print content.string
# print number.string
# 重构代码
items = object_bs.body.find_all('div', {'class':'article block untagged mb15'})
for item in items:
if item.find('div',{'class':'thumb'})== None:
author = item.find('h2')
content = item.find('div', {'class':'content'})
print author.get_text(), content.get_text()
# for item in items:
# havaImg = re.search("img", item[3])
# if not havaImg:
# print item[0], item[1], item[2]
except urllib2.URLError, e:
if hasattr(e, "code"):
print e.code
if hasattr(e, "reason"):
print e.reason
使用面向对象完善交互
这里将上面已经实现的核心功能使用Python面向对象的知识进行封装,并完善交互功能,使用户可以在Pycharm的控制台进行的简单的交互:按下“回车”可以浏览下一条段子的作者和内容。实现的代码如下:
# -*- coding: UTF-8 -*-
__author__ = 'ZYT'
import urllib
import urllib2
import re
import thread
from bs4 import BeautifulSoup
class QSBK:
# 初始化方法,定义一些变量
def __init__(self):
self.pageIndex = 1
self.user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
self.headers = {'User-Agent' : self.user_agent}
self.stories = []
self.enable = False
# 传入某一页的索引获取页面代码
def getPage(self, pageIndex):
try:
url = 'http://www.qiushibaike.com/hot/page/' + str(pageIndex)
# 构建请求的request
request = urllib2.Request(url, headers=self.headers)
# 利用urlopen获取页面代码
response = urllib2.urlopen(request)
# 将页面转换成UTF-8编码
pageCode = response.read().decode('utf-8')
return pageCode
except urllib2.URLError, e:
if hasattr(e, "reason"):
print u"链接糗事百科页面失败,错误原因:", e.reason
return None
# 传入某一页面代码,放回本页面中不带图片的段子列表
def getPageItems(self, pageIndex):
pageCode = self.getPage(pageIndex)
if not pageCode:
print "页面加载失败。。。"
return None
pageStories = []
object_bs = BeautifulSoup(pageCode, "html.parser")
# 重构代码
items = object_bs.body.find_all('div', {'class': 'article block untagged mb15'})
for item in items:
if item.find('div', {'class': 'thumb'}) == None:
author = item.find('h2')
content = item.find('div', {'class': 'content'})
# print author.get_text(), content.ge
# t_text()
pageStories.append([author.get_text(), content.get_text()])
return pageStories
# 加载并提取页面的内容,加入到列表中
def loadPage(self):
# 如果当前未看的页数少于两页,则加载下一页
if self.enable == True:
if len(self.stories) < 2:
# 获取新的一页
pageStories = self.getPageItems(self.pageIndex)
# 将该页的段子内容放到全局的List中
if pageStories:
self.stories.append(pageStories)
self.pageIndex += 1
# 调用该方法,每次敲击回车打印一个段子
def getOneStory(self, pageStroies, page):
for story in pageStroies:
# 等待用户输入
input = raw_input()
# 每次输入回车一次,判断一下是否需要加载新页面
self.loadPage()
# 如果输入Q则程序结束
if input == 'Q':
self.enable = False
return
print u"第%d页\t发布人:%s\t内容:%s\n" %(page,story[0],story[1])
# 开始方法
def start(self):
print u"正在读取糗事百科,按回车查看新段子,Q退出"
self.enable = True
self.loadPage()
nowPage = 0
while self.enable :
if len(self.stories)>0:
pageStories = self.stories[0]
nowPage+=1
del self.stories[0]
self.getOneStory(pageStories, nowPage)
# 运行程序
ler = QSBK()
ler.start()