Python爬虫实战六之抓取爱问知识人问题并保存至数据库

  • Urllib的用法及异常处理
  • Beautiful Soup的简单应用
  • MySQLdb的基础用法

框架思路

首先我们随便找一个分类地址,外语学习 – 爱问知识人,打开之后可以看到一系列的问题列表。

我们在这个页面需要获取的东西有:

总的页码数,每一页的所有问题链接。

接下来我们需要遍历所有的问题,来抓取每一个详情页面,提取问题,问题内容,回答者,回答时间,回答内容。

最后,我们需要把这些内容存储到数据库中。

要点简析

1.日志输出

日志输出,我们要输出时间和爬取的状态,比如像下面这样:

[2015-08-10 03:05:20] 113011 号问题存在其他答案 我个人认为应该是樱桃沟很美的

[2015-08-10 03:05:20] 保存到数据库,此问题的ID为 113011

[2015-08-10 03:05:20] 当前爬取第 2 的内容,发现一个问题 百度有一个地方,花儿带着芳香,水儿流淌奔腾是什么意思 多多帮忙哦 回答数量 1

[2015-08-10 03:05:19] 保存到数据库,此问题的ID为 113010

所以,我们需要引入时间函数,然后写一个获取当前时间的函数

import time
 
#获取当前时间
def getCurrentTime(self):
    return time.strftime('[%Y-%m-%d %H:%M:%S]',time.localtime(time.time()))
    
#获取当前时间
def getCurrentDate(self):
    return time.strftime('%Y-%m-%d',time.localtime(time.time()))

然后我们需要将缓冲区设置输出到log中

f_handler=open('out.log', 'w') 
sys.stdout=f_handler

这样,所有的print语句输出的内容就会保存到out.log文件中了。

4.保存到数据库

在这里,想实现一个通用的方法,就是把存储的一个个内容变成字典的形式,然后执行插入语句的时候,自动构建对应的sql语句,插入数据。

#构造最佳答案的字典
good_ans_dict = {
        "text": good_ans[0],
        "answerer": good_ans[1],
        "date": good_ans[2],
        "is_good": str(good_ans[3]),
        "question_id": str(insert_id)
        }

构造sql语句并插入到数据库的方法如下:

#插入数据
def insertData(self, table, my_dict):
     try:
         self.db.set_character_set('utf8')
         cols = ', '.join(my_dict.keys())
         values = '"," '.join(my_dict.values())
         sql = "INSERT INTO %s (%s) VALUES (%s)" % (table, cols, '"'+values+'"')
         try:
             result = self.cur.execute(sql)
             insert_id = self.db.insert_id()
             self.db.commit()
             #判断是否执行成功
             if result:
                 return insert_id
             else:
                 return 0
         except MySQLdb.Error,e:
             #发生错误时回滚
             self.db.rollback()
             #主键唯一,无法插入
             if "key 'PRIMARY'" in e.args[1]:
                 print self.getCurrentTime(),"数据已存在,未插入数据"
             else:
                 print self.getCurrentTime(),"插入数据失败,原因 %d: %s" % (e.args[0], e.args[1])
     except MySQLdb.Error,e:
         print self.getCurrentTime(),"数据库错误,原因%d: %s" % (e.args[0], e.args[1])

这里我们只需要传入那个字典,便会构建出对应字典键值和键名的sql语句,完成插入。

5.PHP读取日志

将运行结果输出到了日志里,那么怎么查看日志呢?很简单,在这里提供两种方法

方法一:

PHP倒序输出所有日志内容

<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="refresh" content = "5"> 
    </head>
    <body>
        <?php
            $fp = file("out.log");
            if ($fp) {
                for($i = count($fp) - 1;$i >= 0; $i --) 
                echo $fp[$i]."<br>";
            }
        ?>
    </body>
</html>

此方法可以看到所有的输入日志,但是如果日志太大了,那么就会报耗费内存太大,无法输出。为此我们就有了第二种方法,利用linux命令,输出后十行内容。

方法二:

<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="refresh" content = "5"> 
    </head>
    <body>
        <?php 
            $ph = popen('tail -n 100 out.log','r');
            while($r = fgets($ph)){
                echo $r."<br>";
            }
            pclose($ph);
        ?>
    </body>
</html>

上面两种方法都是5秒刷新一次网页来查看最新的日志。

源代码放送

spider.py

# -*- coding:utf-8 -*-
 
import urllib
import urllib2
import re
import time
import types
import page
import mysql
import sys
from bs4 import BeautifulSoup
 
class Spider:
    
    #初始化
    def __init__(self):
        self.page_num = 1
        self.total_num = None
        self.page_spider = page.Page()
        self.mysql = mysql.Mysql()
        
    #获取当前时间
    def getCurrentTime(self):
        return time.strftime('[%Y-%m-%d %H:%M:%S]',time.localtime(time.time()))
    
    #获取当前时间
    def getCurrentDate(self):
        return time.strftime('%Y-%m-%d',time.localtime(time.time()))
    
    #通过网页的页码数来构建网页的URL

page.py

# -*- coding:utf-8 -*-
import urllib
import urllib2
import re
import time
import types 
import tool
from bs4 import BeautifulSoup
 
#抓取分析某一问题和答案
class Page:
    
    def __init__(self):
        self.tool = tool.Tool()
    
    #获取当前时间
    def getCurrentDate(self):
        return time.strftime('%Y-%m-%d',time.localtime(time.time()))
    
    #获取当前时间
    def getCurrentTime(self):
        return time.strftime('[%Y-%m-%d %H:%M:%S]',time.localtime(time.time()))
 
    #通过页面的URL来获取页面的代码
    def getPageByURL(self, url):
        try:
            request = urllib2.Request(url)
            response = urllib2.urlopen(request)
            return response.read().decode("utf-8") 
        except urllib2.URLError, e:

tool.py

#-*- coding:utf-8 -*-
import re
 
#处理页面标签类
class Tool:
    
    #将超链接广告剔除
    removeADLink = re.compile('<div class="link_layer.*?</div>')
    #去除img标签,1-7位空格,&nbsp;
    removeImg = re.compile('<img.*?>| {1,7}|&nbsp;')
    #删除超链接标签
    removeAddr = re.compile('<a.*?>|</a>')
    #把换行的标签换为\n
    replaceLine = re.compile('<tr>|<div>|</div>|</p>')
    #将表格制表<td>替换为\t
    replaceTD= re.compile('<td>')
    #将换行符或双换行符替换为\n
    replaceBR = re.compile('<br><br>|<br>')
    #将其余标签剔除
    removeExtraTag = re.compile('<.*?>')

mysql.py

# -*- coding:utf-8 -*-
 
 
import MySQLdb
import time
 
class Mysql:
    
    #获取当前时间
    def getCurrentTime(self):
        return time.strftime('[%Y-%m-%d %H:%M:%S]',time.localtime(time.time()))
    
    #数据库初始化
    def __init__(self):
        try:
            self.db = MySQLdb.connect('ip','username','password','db_name')
            self.cur = self.db.cursor()
        except MySQLdb.Error,e:
             print self.getCurrentTime(),"连接数据库错误,原因%d: %s" % (e.args[0], e.args[1])
 
    #插入数据
    def insertData(self, table, my_dict):
         try:
             self.db.set_character_set('utf8')
             cols = ', '.join(my_dict.keys())
             values = '"," '.join(my_dict.values())
             sql = "INSERT INTO %s (%s) VALUES (%s)" % (table, cols, '"'+values+'"')
             try:
                 result = self.cur.execute(sql)
                 insert_id = self.db.insert_id()
                 self.db.commit()
                 #判断是否执行成功
                 if result:
                     return insert_id
                 else:
                     return 0
             except MySQLdb.Error,e:
                 #发生错误时回滚
                 self.db.rollback()
                 #主键唯一,无法插入
                 if "key 'PRIMARY'" in e.args[1]:
                     print self.getCurrentTime(),"数据已存在,未插入数据"
                 else:
                     print self.getCurrentTime(),"插入数据失败,原因 %d: %s" % (e.args[0], e.args[1])
         except MySQLdb.Error,e:
             print self.getCurrentTime(),"数据库错误,原因%d: %s" % (e.args[0], e.args[1])

数据库建表SQL如下:

CREATE TABLE IF NOT EXISTS `iask_answers` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `text` text NOT NULL COMMENT '回答内容',
  `question_id` int(18) NOT NULL COMMENT '问题ID',
  `answerer` varchar(255) NOT NULL COMMENT '回答者',
  `date` varchar(255) NOT NULL COMMENT '回答时间',
  `is_good` int(11) NOT NULL COMMENT '是否是最佳答案',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
 
CREATE TABLE IF NOT EXISTS `iask_questions` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '问题ID',
  `text` text NOT NULL COMMENT '问题内容',
  `questioner` varchar(255) NOT NULL COMMENT '提问者',
  `date` date NOT NULL COMMENT '提问时间',
  `ans_num` int(11) NOT NULL COMMENT '回答数量',
  `url` varchar(255) NOT NULL COMMENT '问题链接',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

运行的时候执行如下命令即可:nohup python spider.py & 

运行结果查看

我们把PHP文件和log文件放在同一目录下,运行PHP文件,便可以看到如下的内容:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值