Python之Scrapy初学问题集中(二)【爬取的数据为何数据库中没有??(解决方案)】|【初级爬虫程序】

这次就是由于一个问题,引出了一系列的思路

问题是:scrapy爬取的数据控制台已经有内容输出,但是数据库中没有?
下面是我过程中的问题:其实大多数的代码问题都是由于自己代码不熟练造成的

在这里插入图片描述
圈出来的内容在编写中是不能随意改变得(三种数据库的pipelines的写法结构相同)
解答:我的错误就是由于将process_item ,顺手错写成了process_spider,导致数据无法放入数据库,而且各种求教,解决都不行,最后检查代码才发现

下方是完整正确的代码

项目包结构:
在这里插入图片描述

items.py

import scrapy
class QidianHotItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()#书名
    author = scrapy.Field()#作者
    type = scrapy.Field()#类型
    status=scrapy.Field()#小说目前的状态(连载或完结)
    info = scrapy.Field()#小说简介
    up_date = scrapy.Field()#最近更新

qidian_hot_spider.py

#coding:utf-8
#爬取起点中文网的小说信息

from scrapy import Request
from scrapy.spiders import Spider
from qidian_hot.items import QidianHotItem 
from scrapy.loader import ItemLoader
class HotSaleSpider(Spider):
    name="hot"#爬虫名称
    
    #伪装浏览器
    def start_requests(self):
        url="https://www.qidian.com/rank/hotsales?style=1&page=1"
        self.current_page=1
        yield Request(url)
        #Request(url, callback, method, headers, body, cookies, meta, encoding, priority, dont_filter, errback, flags)
    def parse(self, response):  #数据解析
        list_selector = response.xpath("//div[@class='book-mid-info']")
        
        #使用xpath定位
        for one_selector in list_selector:
            #获取小说信息
            name=one_selector.xpath("h4/a/text()").extract()[0]
                   
            #小说作者
            author=one_selector.xpath("p[1]/a[1]/text()").extract()[0]
              
            #小说类型
            type=one_selector.xpath("p[1]/a[2]/text()").extract()[0]
              
            #状态
            status=one_selector.xpath("p[1]/span/text()").extract()[0]
              
            #小说简介
            info=one_selector.xpath("p[2]/text()").extract()[0]
             
            #更新
            up_date = one_selector.xpath("p[3]/a/text()").extract()[0]
             
            #使用items
            item = QidianHotItem()
            item["name"] = name
            item["author"]=author
            item["type"]=type
            item["status"]=status
            item["info"]=info
            item["up_date"]=up_date
            yield item
            #获取下一页的数据
            self.current_page+=1
            if self.current_page<=2:
                next_url="https://www.qidian.com/rank/hotsales?style=1&page=%d"%self.current_page
                yield Request(next_url)

settings.py

USER_AGENT ="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
ROBOTSTXT_OBEY = False  #不遵守robots.txt 规则
#初始状态是默认关闭的      300代表的是先后顺序,在多个管道的时候
ITEM_PIPELINES = {
    'qidian_hot.pipelines.QidianHotPipeline': 300,
#     'qidian_hot.pipelines.MongoDB_Spider': 400, #这是MongoDB数据库的管道
    'qidian_hot.pipelines.Redis_Spider': 400,  #这是redis数据库的管道
#     'qidian_hot.pipelines.MySQLPipeline': 500,  #这是mysql数据库
}

三种数据库的配置项,书写在settings.py文件中

#数据库  MySQL
MYSQL_DB_NAME = "hot_qidian"
MYSQL_HOST = "localhost"
MYSQL_USER = "root"
MYSQL_PASSWORD = "123456"
#数据库MongoDB
MONGODB_HOST = "127.0.0.1"
MONGODB_PORT = 27017
MONGODB_NAME = "qidian"
MONGODB_COLLECTION = "hot"       
#Redis 数据库
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB_INDEX = 1

1、使用MySQL数据库

class MySQLPipeline(object):
    #在spider开始之前,调用一次
    def open_spider(self,spider):
        db_name = spider.settings.get("MYSQL_DB_NAME","hot_qidian")
        host = spider.settings.get("MYSQL_HOST","localhost")
        user = spider.settings.get("MYSLQ_USER","root")
        password = spider.settings.get("MYDSQL_PASSWORD","123456")
      #连接数据库
        self.db_conn = MySQLdb.connect(db = db_name,
                                       host = host,
                                       user = user,
                                       password = password,
                                       charset = "utf8"
                                        )
        self.db_cursor = self.db_conn.cursor()  #得到游标
      
    #处理每一个item
    def process_item(self,item,spider):
        values = (item["name"],item["author"],item["type"],item["status"],item["up_date"])
        #确定sql语句
        sql = 'insert into hot(name,author,type,status,up_date) values(%s,%s,%s,%s,%s)'
        self.db_cursor.execute(sql,values)
        return item
      
    #在spider结束时,调用一次
    def close_spider(self,spider):
        self.db_conn.commit()  #提交数据 
        self.db_cursor.close()
        self.db_conn.close()

一次使用成功。
2、MongoDB数据库

import pymongo     
class MongoDB_Spider(object):
    #开始之前调用一次
    def open_sipder(self,spider):
        host = spider.settings.get('MONGODB_HOST')
        port = spider.settings.get('MONGODB_PORT')
        db_name = spider.settings.get('MONGODB_NAME')
        db_collection = spider.settings.get('MONGODB_COLLECTION')
        self.db_client = pymongo.MongoClient(host=host,port = port)
        #指定数据库
        self.db_name = self.db_client[db_name]
        #指定集合,得到一个集合对象
        self.db_collection = self.db_name[db_collection]
             
    #处理每一个item数据
    def process_item(self,item,spider):
        item_hot = dict(item)
        self.db_collection.insert(item_hot)
    #结束时,调用一次
    def close_spider(self,spider):
        self.db_client.close()

3、连接redis数据库

import redis
class Redis_Spider(object):
    num = 1
    def __init__(self):
        self.item_set=set()
    def open_spider(self,spider):
        host = spider.settings.get("REDIS_HOST","localhost")
        port = spider.settings.get("REDIS_PORT",6379)
        db_index = spider.settings.get("REDIS_DB_INDEX",1)
        self.db_conn = redis.Redis(host=host,port=port,password='',db=db_index)
        #将数据存储到数据库中
    def process_item(self,item,spider):
        print(self.db_conn)
        try:
            item_dict = dict(item)
            self.db_conn.rpush("novel",item_dict)
            return item
        except Exception as ex:
            print(ex)
    def close_spider(self,spider):#关闭
        self.db_conn.connection_pool.disconnect()
      

上面的代码运行是无错的

课程目标 《从零开始学Scrapy网络虫》从零开始,循序渐进地介绍了目前流行的网络虫框架Scrapy。即使你没有任何编程基础,学习起来也不会有压力,因为我们有针对性地介绍了Python编程技术。另外,《从零开始学Scrapy网络虫》在讲解过程以案例为导向,通过对案例的不断迭代、优化,让读者加深对知识的理解,并通过14个项目案例,提高学习者解决实际问题的能力。 适合对象 初学者、虫爱好者、高校相关专业的学生、数据虫工程师。 课程介绍 《从零开始学Scrapy网络虫》共13章。其,第1~4章为基础篇,介绍了Python基础、网络虫基础、Scrapy框架及基本的虫功能。第5~10章为进阶篇,介绍了如何将数据存储于MySQL、MongoDB和Redis数据;如何实现异步AJAX数据;如何使用Selenium和Splash实现动态网站的;如何实现模拟登录功能;如何突破反虫技术,以及如何实现文件和图片的下载。第11~13章为高级篇,介绍了使用Scrapy-Redis实现分布式虫;使用Scrapyd和Docker部署分布式虫;使用Gerapy管理分布式虫,并实现了一个抢票软件的综合项目。       由于目标网站可能会对页面进行改版或者升级反虫措施,如果发现视频的方法无法成功数据,敬请按照页面实际情况修改XPath的路径表达式。视频教程主要提供理论、方法支撑。我们也会在第一时间更新源代码,谢谢! 课程特色
本人小白一枚,刚接触Scrapy框架没多久,写了一个简单的Spider,但是发现每一次后的结果都比网页上的真实数据量要少,比如网站上一共有100条,但我下来的结果一般会少几条至几十条不等,很少有100条齐的时候。 整个虫有两部分,一部分是页面的横向(进入下一页),另一个是纵向的(进入页面每一产品的详细页面)。之前我一直以为是pipelines存储到excel的时候数据丢失了,后来经过Debug调试,发现是在Spider数据就遗漏了,def parse函数的item数量是齐的,包括yield Request加入到队列,但是调用def parse_item函数时,就有些产品的详细页面无法进入。这是什么原因呢,是因为Scrapy异步加载受网速之类的影响么,本身就有缺陷,还是说是我设计上面的问题?有什么解决的方法么,不然数据量一大那丢失的不是就很严重么。 求帮助,谢谢各位了。 ``` class MyFirstSpider(Spider): name = "MyFirstSpider" allowed_doamins = ["e-shenhua.com"] start_urls = ["https://www.e-shenhua.com/ec/auction/oilAuctionList.jsp?_DARGS=/ec/auction/oilAuctionList.jsp"] url = 'https://www.e-shenhua.com/ec/auction/oilAuctionList.jsp' def parse(self, response): items = [] selector = Selector(response) contents = selector.xpath('//table[@class="table expandable table-striped"]/tbody/tr') urldomain = 'https://www.e-shenhua.com' for content in contents: item = CyfirstItem() productId = content.xpath('td/a/text()').extract()[0].strip() productUrl = content.xpath('td/a/@href').extract()[0] totalUrl = urldomain + productUrl productName = content.xpath('td/a/text()').extract()[1].strip() deliveryArea = content.xpath('td/text()').extract()[-5].strip() saleUnit = content.xpath('td/text()').extract()[-4] item['productId'] = productId item['totalUrl'] = totalUrl item['productName'] = productName item['deliveryArea'] = deliveryArea item['saleUnit'] = saleUnit items.append(item) print(len(items)) # **************进入每个产品的子网页 for item in items: yield Request(item['totalUrl'],meta={'item':item},callback=self.parse_item) # print(item['productId']) # 下一页的跳转 nowpage = selector.xpath('//div[@class="pagination pagination-small"]/ul/li[@class="active"]/a/text()').extract()[0] nextpage = int(nowpage) + 1 str_nextpage = str(nextpage) nextLink = selector.xpath('//div[@class="pagination pagination-small"]/ul/li[last()]/a/@onclick').extract() if (len(nextLink)): yield scrapy.FormRequest.from_response(response, formdata={ *************** }, callback = self.parse ) # 产品子网页内容的抓 def parse_item(self,response): sel = Selector(response) item = response.meta['item'] # print(item['productId']) productInfo = sel.xpath('//div[@id="content-products-info"]/table/tbody/tr') titalBidQty = ''.join(productInfo.xpath('td[3]/text()').extract()).strip() titalBidUnit = ''.join(productInfo.xpath('td[3]/span/text()').extract()) titalBid = titalBidQty + " " +titalBidUnit minBuyQty = ''.join(productInfo.xpath('td[4]/text()').extract()).strip() minBuyUnit = ''.join(productInfo.xpath('td[4]/span/text()').extract()) minBuy = minBuyQty + " " + minBuyUnit isminVarUnit = ''.join(sel.xpath('//div[@id="content-products-info"]/table/thead/tr/th[5]/text()').extract()) if(isminVarUnit == '最小变量单位'): minVarUnitsl = ''.join(productInfo.xpath('td[5]/text()').extract()).strip() minVarUnitdw = ''.join(productInfo.xpath('td[5]/span/text()').extract()) minVarUnit = minVarUnitsl + " " + minVarUnitdw startPrice = ''.join(productInfo.xpath('td[6]/text()').extract()).strip().rstrip('/') minAddUnit = ''.join(productInfo.xpath('td[7]/text()').extract()).strip() else: minVarUnit = '' startPrice = ''.join(productInfo.xpath('td[5]/text()').extract()).strip().rstrip('/') minAddUnit = ''.join(productInfo.xpath('td[6]/text()').extract()).strip() item['titalBid'] = titalBid item['minBuyQty'] = minBuy item['minVarUnit'] = minVarUnit item['startPrice'] = startPrice item['minAddUnit'] = minAddUnit # print(item) return item ```
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页