使用Python爬虫实现获取糗事百科数据

注意:原文章写于2016年12月

Python爬取目标

  • 抓取糗事百科页面中的热门段子(包括作者和内容)
  • 过滤带有图片的段子内容(Pycharm控制台无法输出图片)
  • 使用Python面向对象对功能进行封装,并在控制台实现,敲击一次回车键显示一个段子作者和内容的功能。

功能实现

确定页面的HTML结构:确定需要抓取的页面为:http://www.qiushibaike.com/hot/,并在浏览器中使用F12功能,确定该网页的HTML结构,这里可以发现,需要抓取的内容的结构如下:

image

可知:

  • 需要的所有段子信息均存放在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()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值