Logo

郎哥编程

配置文件与日志

2020-12-10 279

当前百度新闻爬虫项目将爬取的数据输出到了JSON文件,在实际应用中,一般会将爬取的数据存储到数据库,方便后续程序对爬取的数据进行分析和处理。

若希望百度新闻爬虫项目将爬取的数据存储到数据库,该做哪些工作呢?数据库服务器的地址、登录账号和密码等信息要放置到项目的什么位置呢?

1、初步认识配置文件

现在就要用到Scrapy的配置文件了,配置文件就在项目的根目录下,文件名称是settings.py。

爬虫项目创建完成后,settings.py的主要内容如下:

BOT_NAME = 'newsbaidu'
SPIDER_MODULES = ['newsbaidu.spiders']
NEWSPIDER_MODULE = 'newsbaidu.spiders'
ROBOTSTXT_OBEY = True
# 项目新添加的配置项
FEED_EXPORT_ENCODING = 'utf-8'

配置文件的注释行没有列出来,其中一些默认的配置项也被注释了,若要用到这些配置项,需要把注释去掉。

配置项是一个键值对,键是配置项的名称,值是配置项的内容。Scrapy框架应用配置文件里的多个配置项来定制或扩展爬虫的行为和功能,多个配置项为一个配置组,主要有项目信息、数据爬取方式、爬取日志与统计、爬取性能、文件下载、管道、Scrapy扩展等配置组。

例如在上面的配置文件中,项目信息配置组有下面的配置项:

BOT_NAME = 'newsbaidu'
SPIDER_MODULES = ['newsbaidu.spiders']
NEWSPIDER_MODULE = 'newsbaidu.spiders'

配置项BOT_NAME配置了爬虫项目的名称,该名称也是日志记录的名称;配置项SPIDER_MODULES存储了项目拥有的爬虫模块,配置项的值是一个列表对象,可以存储多个爬虫模块;配置项NEWSPIDER_MODULE存储了使用genspide命令创建新爬虫时,爬虫程序文件存储的包路径。

项目添加的配置项FEED_EXPORT_ENCODING用于解决中文编码问题,该配置项可以设置输出文件的字符编码方式,scrapy输出文件的默认字符编码是ASCII,ASCII编码不能表示中文字符,因此在输出的JSON文件内,中文字符会显示为16进制的字符编码,要解决这个问题,就需要在在setting.py文件添加配置项FEED_EXPORT_ENCODING,将scrapy输出文件字符编码设置为utf-8。

2、 输出爬虫运行日志

运行日志就是记录爬虫在运行过程中的状态、行为、异常信息等内容,通过分析运行日志,可以实现对爬虫的运行状态的分析、调试及错误定位。

Scrapy框架默认是不输出运行日志的,要让爬虫程序输出运行日志,需要做下面一些工作。

一、在配置文件内添加日志配置项

Scrapy对日志的输出信息进行了等级划分,共有五个等级:

1、CRITICA:严重错误(critical)
2、ERROR:一般错误(regular errors)
3、 WARNING:警告信息(warning messages)
4 、INFO:一般信息(informational messages)
5 、 DEBUG:调试信息(debugging messages)

数字越小等级越高,最高等级是发生严重错误,最低等级是调试信息,日志输出信息划分等级可以对输出的日志信息进行调整,避免输出不必要的日志信息。

若是程序在调试过程,可以设置日志等级为DEBUG,所有等级的日志信息都会输出到日志文件;若是程序进入正常运行,可以设置日志等级为WARNING,WARNING及以上的等级日志信息会被输出到日志文件。

日志输出等级的设置放置在配置文件内,在配置文件尾部添加LOG_LEVEL配置项:

# 日志配置
LOG_LEVEL ='INFO'
日志要输出到文件,在配置文件内还要配置日志输出文件的路径和文件名称。配置文件路径和名称的配置项是LOG_FILE。
# 日志配置
LOG_LEVEL ='INFO'
LOG_FILE ='./baidnews.log'

“./baidnews.log”是在当前程序运行的目录下输出baidnews.log日志文件。该配置项将会导致日志信息输出到文件而不是控制台。

二、在代码内输出日志信息

Python提供的logging日志模块可以输出日志信息。在spider_newsbaidu.py文件内添加下面的代码:

# 导入日志模块
import logging
# 创建日志实例对象
logger = logging.getLogger("SpiderNewsbaiduSpider")

logging模块的getLogger()方法获取Logger实例对象,传入的字符串参数设置输出日志的模块名称。

在SpiderNewsbaiduSpider类parse()方法内部的for循环结构内添加下面的代码:

logger.info(str(item_node))

info()方法是Logger实例对象输出info级别的信息。

spider_newsbaidu.py完整代码如下:

import scrapy
# 导入scrapy选择器
from scrapy.selector import Selector
# 导入NewsbaiduItem
from newsbaidu.items import NewsbaiduItem
# 导入BaiduNewsLoader
from newsbaidu.newsitemload import BaiduNewsLoader
# 导入日志模块
import logging
# 创建日志实例对象
logger = logging.getLogger("SpiderNewsbaiduSpider")
class SpiderNewsbaiduSpider(scrapy.Spider):
    name = 'spider_newsbaidu'
    allowed_domains = ['https://news.baidu.com']
    start_urls = ['https://news.baidu.com/']
    def parse(self, response):
        # 获取爬取下来的网页代码
        html = response.text
        # 处理新闻类别网页
        # 使用xpath表达式搜寻新闻类别超链接标签
        category_node = response.xpath("//div[@id='channel-all']/div/ul/li[position()>1]/a/@href").extract()
        for request_node in category_node:
            url = response.urljoin(request_node)
            request = scrapy.Request(url,callback=self.parse_category,dont_filter=True)
            yield request
        # 使用xpath表达式搜寻指定的a标签节点,节点以列表方式返回
        item_nodes = response.xpath("//a[contains(@mon,'ct=1')]").extract()
        # 遍历节点
        for item_node in item_nodes:
            # 输出info级别的日志信息
            logger.info(str(item_node))
            # 实例化BaiduNewsLoader对象
            loader = BaiduNewsLoader(item=NewsbaiduItem(), selector=Selector(text=str(item_node)))
            # 提取并清洗news_title数据项
            print(loader.add_xpath("news_title","//text()"))
            # 提取并清洗news_link数据项
            loader.add_xpath("news_link","//@href")
            # 获取收集的news_title数据项的值
            value = loader.get_collected_values("news_title")
            # 若value不为None,调用yield语句返回Item数据项
            if value:
                yield loader.load_item()
 
    # 处理类别网页的回调方法
    def parse_category(self, response):
         html = response.text
         # 解析新闻类别名称
         category = response.xpath("//li[contains(@class,'current active')]/a/text()").extract()
         # 使用xpath表达式搜寻指定的a标签节点,节点以列表方式返回
         item_nodes = response.xpath("//a[contains(@mon,'col') and not(contains(@mon,'col=carouse'))]").extract()
         # 遍历节点
         for item_node in item_nodes:
             # 实例化BaiduNewsLoader对象
             loader = BaiduNewsLoader(item=NewsbaiduItem(), selector=Selector(text=str(item_node)))
             pre_category = ["(" + category[0] + ")"]
             # 添加新闻类别名称
             loader.add_value("news_title",pre_category)
             # 天机新闻条目标题
             loader.add_xpath("news_title","//text()")
             # 使用Selector选择器获取超超链接的文本
             loader.add_xpath("news_link","//@href")
             # 获取收集的news_title数据项的值
             value = loader.get_collected_values("news_title")
             # 若value不为None,调用yield语句返回Item数据项
             if value:
                 yield loader.load_item()

3、 读取配置项

在一些情况下,需要在程序内读取配置文件的配置项。Scrapy框架的utils.project模块提供了get_project_settings()函数,用于获取操作配置文件的字典对象。

访问配置文件配置项的案例代码:

#导入settings配置读取函数
from scrapy.utils.project import get_project_settings
# 获取操作配置文件的字典对象
settings = get_project_settings()
# 读取 LOG_FILE配置项
logfile=settings[' LOG_FILE ']

读取配置项的案例代码参见后面的课程案例。

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论