zoukankan      html  css  js  c++  java
  • 《学习scrapy框架爬小说》的进一步完善

    一、完善目标:

    1、为方便使用,把小说拼音或英文名,小说输出中文名,第一章节url地址变量化,修改这些参数即可爬取不同的小说。

    2、修改settings.py设置文件,配置为记录debug的log信息,以方便排错。

    3、修改字符集编码,解决部分网页有emoji符号,导致无法把爬取的网页内容存入数据表的问题。(如:http://www.xbiquge.la/43/43474/19425972.html页面出现了emoji符号)

    二、实施过程

    1、修改pipelines.py文件:

    (python) [root@localhost xbiquge]# vi xbiquge/pipelines.py
            self.url_firstchapter = "http://www.xbiquge.la/43/43474/19425971.html"  #此处为小说的第一章节链接地址。
    # -*- coding: utf-8 -*-

    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    import os
    import time
    import pymysql
    from twisted.enterprise import adbapi
    from pymysql import cursors

    class XbiqugePipeline(object):
        #定义类初始化动作,包括连接数据库novels及建表
        def __init__(self):
            dbparams = {
                'host':'127.0.0.1',
                'port':3306,
                'user':'root',
                'password':'password',
                'database':'novels',
                'charset':'utf8mb4'   #使用utf8mb4字符集可避免emoji表情符号无法存入数据表的错误,这是因为mysql的utf8只支持3个字节的存储,而一般字符是3个字节,但是emoji表情符号是4字节。(参见:《MySQL插入emoji表情错误的3种解决方案,Incorrect string value: 'xF0x9Fx98x84'》https://blog.csdn.net/dmw412724/article/details/81119325)

            }
            self.conn = pymysql.connect(**dbparams)
            self.cursor = self.conn.cursor()
            self._sql = None
            self.name_novel = "heifen"   #此处为小说的英文或拼音名,此名也是小说存储表文件名。
            self.url_firstchapter = "http://www.xbiquge.la/43/43474/19425948.html"  #此处为小说的第一章节链接地址。
            self.name_txt = "老婆的头号黑粉"   #此处为小说的中文名称,输出文件以此命名。

        #爬虫开始
        def open_spider(self,spider):
            self.createtable()  #爬虫开始时先初始化小说存储表
            return

        #建表
        def createtable(self):
            self.cursor.execute("drop table if exists "+ self.name_novel)
            self.cursor.execute("create table " + self.name_novel + " (id int unsigned auto_increment not null primary key, url varchar(50) not null, preview_page varchar(50), next_page varchar(50), content TEXT not null) charset=utf8mb4")
            return

        def process_item(self, item, spider):
            self.cursor.execute(self.sql, (item['url'], item['preview_page'], item['next_page'], item['content']))
            self.conn.commit()
            return item

        @property
        def sql(self):
            if not self._sql:
                self._sql = """
                    insert into """ + self.name_novel + """(id, url, preview_page, next_page, content) values(null, %s, %s, %s, %s)
                    """
                return self._sql
            return self._sql

        #从数据库取小说章节内容写入txt文件
        def content2txt(self):
            self.cursor.execute("select count(*) from " + self.name_novel)
            record_num = self.cursor.fetchall()[0][0]
            print(record_num)
            counts=record_num
            url_c = """+self.url_firstchapter+"""
            start_time=time.time()  #获取提取小说内容程序运行的起始时间
            f = open(self.name_txt+".txt", mode='w', encoding='utf-8')   #写方式打开小说名称加txt组成的文件
            for i in range(counts):
                sql_c = "select content from " + self.name_novel + " where url=" + url_c  #组合获取小说章节内容的sql命令。此处需要修改数据库文件名称
                self.cursor.execute(sql_c)
                record_content_c2a0=self.cursor.fetchall()[0][0]  #获取小说章节内容
                record_content=record_content_c2a0.replace(u'xa0', u'')  #消除特殊字符xc2xa0
                f.write(' ')
                f.write(record_content + ' ')
                f.write(' ')
                sql_n = "select next_page from " + self.name_novel + " where url=" + url_c   #组合获取下一章链接的sql命令。此处需要修改数据库文件名称
                self.cursor.execute(sql_n)
                url_c = """ + self.cursor.fetchall()[0][0] + """  #下一章链接地址赋值给url_c,准备下一次循环。
            f.close()
            print(time.time()-start_time)
            print(self.name_txt + ".txt" + " 文件已生成!")
            return

        #爬虫结束,调用content2txt方法,生成txt文件
        def close_spider(self,spider):
            self.content2txt()
            return

    2、spider文件:

    (python) [root@localhost xbiquge]# vi xbiquge/spiders/heifen.py   #爬虫文件可复制使用,不用再次使用scrapy genspider命令来产生。

    # -*- coding: utf-8 -*-
    import scrapy
    from xbiquge.items import XbiqugeItem

    class SancunSpider(scrapy.Spider):   #此类是由scrapy genspider sancun www.xbiquge.la命令生成,抓取不同小说时,此类名可不用修改。
        name = 'heifen'   #不同的爬虫,此处需要设置不同的名字。
        allowed_domains = ['www.xbiquge.la']
        #start_urls = ['http://www.xbiquge.la/10/10489/']

        def start_requests(self):
            start_urls = ['http://www.xbiquge.la/43/43474/']
            for url in start_urls:
                yield scrapy.Request(url=url, callback=self.parse)

        def parse(self, response):
            dl = response.css('#list dl dd')     #提取章节链接相关信息
            for dd in dl:
                self.url_c = "http://www.xbiquge.la" + dd.css('a::attr(href)').extract()[0]   #组合形成小说的各章节链接
                #print(self.url_c)
                #yield scrapy.Request(self.url_c, callback=self.parse_c,dont_filter=True)
                yield scrapy.Request(self.url_c, callback=self.parse_c)    #以生成器模式(yield)调用parse_c方法获得各章节链接、上一页链接、下一页链接和章
    节内容信息。
                #print(self.url_c)
        def parse_c(self, response):
            item = XbiqugeItem()
            item['url'] = response.url
            item['preview_page'] = "http://www.xbiquge.la" + response.css('div .bottem1 a::attr(href)').extract()[1]
            item['next_page'] = "http://www.xbiquge.la" + response.css('div .bottem1 a::attr(href)').extract()[3]
            title = response.css('.con_top::text').extract()[4]
            contents = response.css('#content::text').extract()
            text=''
            for content in contents:
                text = text + content
            #print(text)
            item['content'] = title + " " + text.replace('15', ' ')    #各章节标题和内容组合成content数据,15是^M的八进制表示,需要替换为换行符。
            yield item     #以生成器模式(yield)输出Item对象的内容给pipelines模块。

    3、修改settings文件:

      (python) [root@localhost xbiquge]# vi xbiquge/settings.py

    ...

    ROBOTSTXT_OBEY = False

    ...

    ITEM_PIPELINES = {
        'xbiquge.pipelines.XbiqugePipeline': 300,
    }

    ...

    FEED_EXPORT_ENCODING = 'utf-8'
    LOG_LEVEL = 'DEBUG'
    LOG_FILE =  './myspiders.log'

    4、items.py文件:

    # -*- coding: utf-8 -*-
    # Define here the models for your scraped items
    #
    # See documentation in:
    # https://docs.scrapy.org/en/latest/topics/items.html
    import scrapy
    class XbiqugeItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        url = scrapy.Field()
        preview_page = scrapy.Field()
        next_page = scrapy.Field()
        content = scrapy.Field()

    三、爬取不同小说的使用方法:

    1、拷贝spider文件:cp heifen.py xueba.py

    2、修改新spider文件中的爬虫名(name)和目录页url地址(start_urls):

    (1)name = 'heifen'  修改为name = 'xueba';

    (2)start_urls = ['http://www.xbiquge.la/43/43474/'] 修改为 start_urls = ['http://www.xbiquge.la/19/19639/']

    3、修改pipelines.py文件中三个变量内容:self.name_novel、self.url_firstchapterself.name_txt

    4、运行爬虫程序(在/root/xbiquge目录下):scrapy runspider  xbiquge/spiders/xueba.py

    运行完成,即可在当前目录下(/root/xbiquge)看到生成的小说txt文件。爬虫运行debug信息可在/root/xbiquge/myspiders.log中查看。

  • 相关阅读:
    coredns bug
    Android的Sepolicy
    漫谈fork
    ftrace总结
    Framebuffer
    .net core 5 发送windows10桌面通知
    test_app 测试环境搭建
    GitHub骚操作
    git基于某分支创建新分支
    mysql导入数据load data infile
  • 原文地址:https://www.cnblogs.com/sfccl/p/12055800.html
Copyright © 2011-2022 走看看