Python的Scrapy框架使用中的诸多问题

2020-11-18 17:56:34 浏览数 (1)

一、爬取的数据,在管道中,存入EXCEL

1.1 安装命令: pip install openpyxl

1.2 在pipelines.py中,进行如下操作:

代码语言:txt复制
from openpyxl import Workbook

class MyspiderPipeline:

    # *************************存入excel************************
    def __init__(self):
        self.wb = Workbook()
        self.ws = self.wb.active
        self.ws.append(['教师姓名', '入职时间', '详细信息'])

    def process_item(self, item, spider):
        # print(item)
        line = [item['teacher'], item['entryTime'], item['info']]  # 把数据每一行整理出来
        self.ws.append(line)  # 将数据一行的形式添加到xlsx中
        return item

    def close_spider(self,spider):
        self.wb.save('job.xlsx')  # 保存xlsx文件

    # *************************存入excel************************

二、使用log日志,替代print输出日志信息

2.1 日志配置方法

在settings.py中,添加如下设置:

代码语言:txt复制
# 设置日志 

# 1.设置日志等级  (这样在控制台输出的信息中就只会有爬取的数据,除非出现warning以上的日志信息。)
LOG_LEVEL = "WARNING"

# 2.保存日志文件到本地
LOG_FILE = './log.log'

2.2 日志使用方法

在其他的py文件中,插入如下代码,即可使用:

代码语言:txt复制
import logging
logger = logging.getLogger(__name__)

from myspider.items import MyspiderItem

class ItcastSpider(scrapy.Spider):
    name = 'itcast'
    allowed_domains = ['itcast.cn']
    start_urls = ['http://www.itcast.cn/channel/teacher.shtml']

    def parse(self, response):
        node_list = response.xpath("//div[@class='main_mask']")
        # print(len(node_list))
        logger.warning("开始爬取数据》》》》")
        for node in node_list:
            item= MyspiderItem()
            #  extract()[0] 在没有值时,会出问题;extract_first()则可以很好地解决这个问题,
            #  没有值则赋值None
            item['teacher'] = node.xpath("./h2/text()").extract_first()
            item['entryTime'] = node.xpath("./h3/text()").extract_first()
            item['info'] = node.xpath("./p/text()").extract_first()
            yield item
        pass

2.3 extract()和extract_first()的区别

extract()0在没有值时,会出问题;extract_first()则可以很好地解决这个问题,没有值则赋值None(代码如上和下方)

代码语言:txt复制
  item['teacher'] = node.xpath("./h2/text()").extract()[0]
  item['entryTime'] = node.xpath("./h3/text()").extract()[0]
  item['info'] = node.xpath("./p/text()").extract()[0]

三、MongoDB的使用

3.1 为什么使用MongoDB

(1) MongoDB旨在为WEB应用提供可扩展的高性能数据存储解决方案。

(2) 由于MongoDB独特的数据处理方式,可以将热点数据加载到内存,故而对查询来讲,会非常快(当然也会非常消耗内存);同时由于采用了BSON的方式存储数据,故而对JSON格式数据具有非常好的支持性以及友好的表结构修改性,文档式的存储方式,数据友好可见;数据库的分片集群负载具有非常好的扩展性以及非常不错的自动故障转移。

3.2 MongoDB安装过程中遇到的问题

(1)下载安装教程地址:[https://www.runoob.com/mongodb/mongodb-window-install.html](https://www.runoob.com/mongodb/mongodb-window-install.html)

(2)安装中的问题:1.下一步安装**"install mongoDB compass"**不勾选;2.在Install a MongoDb as a service选项中

,直接下一步,不要进行任何操作。

3.3 操作mongodb数据库

3.3.1 创建数据库和删除数据库

**创建数据库**:

代码语言:txt复制
              命令行(cmd): use   数据库名

注意:a.**如果数据库不存在则会创建数据库,如果数据库存在则会切换到指定的数据库**

b.如果刚刚创建的数据库不在数据库列表内,如果要显示,则需要向刚刚创建的数据库中插入一些数据才能显示。

向mydb数据库的student集合(表)中添加了一个文档(一条数据):

代码语言:txt复制
                db.student.insert({name:"zhangsan",age:18,gender:1,address:"beijing"}) 

**删除数据库**:

前提:使用当前数据库(use 数据库名)

代码语言:txt复制
                             db.dropDatabase()

3.3.2 查看所有数据库

代码语言:txt复制
             命令:show dbs

3.3.3 查看当前 正在使用的数据库的命令:

代码语言:txt复制
                       a.   db         b.    db.getName()

3.3.4 断开连接

代码语言:txt复制
                     exit

3.3.5 查看命令api

代码语言:txt复制
                 help

3.4 集合操作(表)

3.4.1 查看当前数据库下有哪些集合

代码语言:txt复制
                                     show  collections

3.4.2 创建集合(表)

代码语言:txt复制
                 a.   语法:  db.createCollection("集合名")
                      示例:  db.createCollection("class")
                      
                 b.   语法:db.集合名.insert(document)
                      示例: db.student.insert({name:"lisi",age:18,address:"beijing"})

_**区别**_:两者的区别在于前者创建的是一个空的集合,后者创建一个空的集合(空表)并添加一个文档(一条数据)。

3.4.3 删除当前数据库中的集合

代码语言:txt复制
                            语法:db.集合名.drop()
                            示例: db.class.drop()

3.5 文档操作(数据)

3.5.1 插入文档

a.使用insert()方法插入文档

语法: db.集合名.insert(文档)

代码语言:txt复制
               插入一个: db.student.insert({name:"zhangsan",age:18,gender:1,address:"beijing"})  

语法: db.集合名.insert([文档1,文档2,....,文档n])

代码语言:txt复制
插入多个: db.student.insert([{name:"lisan",age:18,gender:1,address:"beijing"}, {name:"wangwu",
age:16,gender:1,address:"changsha"},{name:"zhangsan",age:88,gender:1,address:"wuhan"}])  

b.使用save()方法插入文档、

语法: db.集合名.save(文档)

说明:如果不指定id字段,save()方法类似于insert()方法,如果指定id字段,则会更新字段的信息。

代码语言:txt复制
              示例1: db.student.save({name:"zhangsan",age:18,gender:1,address:"beijing"})  
代码语言:txt复制
              示例2: 指定id字段: db.student.save({_id:ObjectId("5fb254a355fbfda6785ac809"),
              name:"popoi",age:55,gender:1,address:"beijing"})  

3.5.2 文档更新

a. update()方法,用于更新已经存在的文档(一条数据(一行))

语法:

代码语言:txt复制
                             db.集合名.update(<query>,<update>,{
                                                 upset:<boolean>,
                                                 multi:<booolean>,
                                                 writeConcern:<document>
                                                 })

参数说明:

代码语言:txt复制
                query:  update 的查询条件,类似于sql里update语句内where后面的内容
                update: update的对象和一些更新的操作符($set,$inc)等,$set:直接更新,$inc在原有的
                        基础上累加后更新。
                upset:  可选的,如果不存在update的记录,是否当新数据插入,ture为插入,False为不插入,默认为
                        Flase。
                multi:  可选,mongodb默认是False,只更新找到的第一条记录,如果为True,就按照条件查找出来
                       的数据全部更新。
               writeConcern: 可选,抛出异常的级别。
                

示例: 需求:将popoi的年龄更新为25.

代码语言:txt复制
                   db.student.update({name:"popoi"},{$set:{age:25}})
                   db.student.update({name:"popoi"},{$inc:{age:25}})  //年龄会在原来的基础上加25
                   db.student.update({name:"popoi"},{$set:{age:25}},{multi:true}) //同名的人全部更新

b. save()方法,通过传入的文档替换已有的文档(上面已经说明)

3.5.3 文档删除

说明:在执行remove()函数前,先执行find()命令来判断执行的条件是否存在是一个良好的习惯。

语法:

代码语言:txt复制
               db.集合名.remove(
                       query,
                        {
                           justOne:<boolean>
                           writeConcern:<document>
                        }
               )             

参数说明: query: 可选,删除的文档的条件,(不写则删除全部) justOne: 可选,如果为true或1,则只删除找到的第一个文档(一条数据) writeConcern: 可选,抛出异常的级别。

示例:

代码语言:txt复制
                   db.student.remove({name:"popoi"})  
                   db.student.remove({name:"zhangsan"},{justOne:true}) 

3.5.4 文档查询

a. find()方法查询集合下所有的文档(数据)

代码语言:txt复制
                           语法:db.集合名.find()
                           db.student.find()

b. find()方法查询指定列

代码语言:javascript复制
                       语法: db.集合名.find(
                               query,
                               {
                                   <key>: 1,
                                   <key>: 1
                               }
                       )

参数说明: query: 查询条件 key: 要显示的字段,1表示显示

代码语言:javascript复制
       
             示例: 查询指定:db.student.find({address:"beijing"},{name:1,age:1})
                    查询所有:db.student.find({},{name:1,age:1})

c. **pretty()方法以格式化的方式来显示文档(数据)**

代码语言:javascript复制
                    示例:db.student.find().pretty()
                    

d.findOne()方法查询匹配结果的第一条数据

代码语言:javascript复制
                    示例: db.student.findOne({name:"zhangsan"})

3.5.5 查询条件操作符

a.大于操作 $gt

代码语言:javascript复制
             语法:db.集合.find({<key>:{$gt:<value>}}) 
             示例:db.student.find({age:{$gt:20}})  //年龄大于20的学生

b.大于等于 $gte

代码语言:javascript复制
             语法:db.集合.find({<key>:{$gte:<value>}}) 
             示例:db.student.find({age:{$gte:20}})  

c.小于 $lt

代码语言:javascript复制
             语法:db.集合.find({<key>:{$lt:<value>}}) 
             示例:db.student.find({age:{$lt:20}})  

d.小于等于 $lte

代码语言:javascript复制
             语法:db.集合.find({<key>:{$lte:<value>}}) 
             示例:db.student.find({age:{$lte:20}}) 

e.大于等于和小于等于 $gte 和 $lte

代码语言:javascript复制
             语法:db.集合.find({<key>:{$gte:<value>,$lte:<value>}}) 
             示例:db.student.find({age:{$gte:18,$lte:90}})  //年龄大于18小于90的学生

f.等于

代码语言:javascript复制
             语法:db.集合.find({<key>::<value>}) 
             示例:db.student.find({age:{$gte:18,$lte:90}})  

g.使用_id查询

代码语言:javascript复制
                 示例:db.student.find({"_id":ObjectId("id的值")})  

h.查询某个结果集的数据条数

代码语言:javascript复制
                 示例:db.student.find().count() 

i.查询某个字段的值当中是否包含某个值或字符串

代码语言:javascript复制
                 示例:db.student.find({name:/san/}) 

j.查询某个字段的值是否以某个值或者字符串开头

代码语言:javascript复制
                 示例:db.student.find({name:/ ^zh /}) 

3.5.6 条件查询 and 和 or

a. AND条件

代码语言:javascript复制
            语法: db.集合名.find(条件1,条件2,。。。,条件n)
            示例: db.student.find({age:{$gt:20},address:"beijing"})

a. OR条件

代码语言:javascript复制
            语法: db.集合名.find(
                          {
                               $or:[条件1,条件2,。。。。,条件n]
                          }
            )
            示例: db.student.find({$or:[age:16,age:{$gte:80}]})  //年龄等于16或者年龄大于80的学生

a. AND条件和OR条件联合使用

代码语言:javascript复制
      语法: db.集合名.find(
                          {
                               条件1,
                               条件2,
                               $or:[条件3,条件4,。。。。,条件n]
                          }
            )
            示例: db.student.find({address:"beijing",$or:[age:16,age:{$gte:80}]})  
            //地点在北京的,年龄等于16或者年龄大于80的学生

3.5.7 limit 、skip

a. limit(): 读取指定数量的数据记录

代码语言:javascript复制
               示例: db.student.find().limit(2)

b.skip(): 跳过指定数量的数据

代码语言:javascript复制
              示例: db.student.find().skip(3)                  

c.skip与limit联合使用(通常用这种方式实现分页功能)

代码语言:javascript复制
                示例: db.student.find().skip(3).limit(3)

3.5.8 排序

代码语言:javascript复制
              语法 :db.集合名.find().sort({<key>:1|-1})
              示例:db.student.find().sort({age:1})
              注意: 1表示 升序,-1表示降序。

0 人点赞