Python爬虫的scrapy的学习(学习于b站尚硅谷)

news2024/11/16 3:39:12

目录

  • 一、scrapy
    •   1. scrapy的安装
      •   (1)什么是scrapy
      •   (2)scrapy的安装
    •   2. scrapy的基本使用
      •   (1)scrap的使用步骤
      •   (2)代码的演示
    •   3. scrapy之58同城项目结构和基本方法(注:58同城的数据不是公开数据,不能爬取;本次代码也爬取不到相应的数据)
      •   (1)scrapy项目的组成
      •   (2)scrapy爬虫文件的组成以及响应response的属性和方法
      •   (3)代码演示
    •   4. 汽车之家scrapy工作原理
      •   (1)scrapy架构组成
      •   (2)scrapy的工作原理
      •   (3)代码演示
    •   5.调试工具scrapy shell
      •   (1)什么是scrapy shell
      •   (2)安装ipython
      •   (3)ipython的使用方法
    •   6. scrapy之当当网爬取数据(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)
      •   (1)yied
      •   (2)本节的演示
    •   7.scrapy_当当网管道封装(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)
    •   8.scrapy_当当网开启多条管道下载(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)
    •   9.scrapy_当当网多页下载
    •   10.scrapy_电影天堂多页数据下载
    •   11. scrapy_链接提取器CrawlSpider的使用(含MySql、pymysql的使用)
      •   (1)MySQL的安装和初级使用
      •   (2)CrawlSpider的作用
      •   (3)CrawlSpider的使用方法
      •   (4)代码演示
    •   12.scrapy_crawlspider读书网获取图片的封面地址和名字
      •   (1)CrawlSpider的使用步骤
      •   (2)代码演示
    •   13.scrapy_读书网数据入库和链接跟进(失败,卡在最后的“由于日标计算机积极拒绝”,没有系统学过MySQL,卡住了)
      •   (1)准备工作(安装Ubuntu、在Ubuntu上安装mysql中途含出现的两个问题的解决办法、Windows上安装pymysql)
      •   (2)pymysql的使用步骤
      •   (3)本次的演示(失败,卡在最后的“由于日标计算机积极拒绝”)
    •   14. scrapy_日志信息以及日志级别
      •   (1)日志信息的定义、等级、如何设置日志
      •   (2)代码演示
    •   15.scrapy_百度翻译post请求
      •   (1)scrapy 下的post请求的用法
      •   (2)代码演示

  说明:该文章是学习 尚硅谷在B站上分享的视频 Python爬虫教程小白零基础速通p51-104而记录的笔记,笔记来源于本人,关于python基础可以去CSDN上阅读本人学习黑马程序员的笔记。 若有侵权,请联系本人删除。笔记难免可能出现错误或笔误,若读者发现笔记有错误,欢迎在评论里批评指正。 请合法合理使用爬虫,不爬取任何涉密以及涉及隐私的内容,合理控制请求次数,爬取的内容未经授权请不要用于商用,保护自己,免受牢狱之灾。
在这里插入图片描述
在这里插入图片描述
  本章将介绍scrapy,它是爬虫在企业级研发中用得最多的技术,由于scrapy使用框架,故具有编程更简单、爬取速度更快、更好地进行爬虫的开发。
  注:由于本人是先做word,再将代码复制到CSDN中的,代码可能会出现类似下图的情况,多几个“-”号的问题。代码太多,根本改不完,难免有没改到的。

在这里插入图片描述

一、scrapy

  1. scrapy的安装

  (1)什么是scrapy

  scray是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘、信息处理或存储历史数据等一系列的程序中。
  什么是结构性数据?结构性就是类似的具有相同特征的东西,里面的数据就是结构性数据。
  下面将举一个具体例子进行说明。打开读书网,点击“计算机/网络”。假如我们想采取这个网站中所有书的信息,包括名字、作者、简介、图片等。
在这里插入图片描述
  如下图,选中一本书进行定位(即在某本书处打开检查),发现这些书的信息有一个相同的结构,比如书名都在结构“/html/body/div[6]/div/div[2]/div[2]/ul/li/div/h3/a”下,它们具有相同的结构,这就是结构性的例子。至于结构性数据,比如书名就是该结构下的数据。
在这里插入图片描述
在这里插入图片描述

  (2)scrapy的安装

  安装命令:pip install scrapy -i https://pypi.mirrors.ustc.edu.cn/simple/
  安装具体步骤:如下图,先打开“命令提示符”。
在这里插入图片描述
  然后在命令提示符里安装scrapy。
在这里插入图片描述
在这里插入图片描述

  2. scrapy的基本使用

  (1)scrap的使用步骤

1. 创建爬虫的项目     
    scrapy startproject 项目名字
    注意:项目的名字不允许使用数字开头   也不能包含中文
2. 创建爬虫文件
    要在spiders文件夹中去创建爬虫文件

    进入spiders文件夹:cd 项目的名字\项目的名字\spiders,
    - 本次演示使用的命令为    cd scrapy_baidu_091\scrapy_baidu_091\spiders

    创建爬虫文件
    scrapy genspider 爬虫的名字 要爬取的网页
    eg:scrapy genspider baidu http://www.baidu.com
3. 运行爬虫代码
    scrapy crawl 爬虫的名字
    eg:scrapy crawl baidu
   注:在运行爬虫程序时,需注释掉文件“setting.py”中的“ROBOTSTXT_OBEY = True,  
       即不遵守君子协议

  注意,对于请求的地址,如果含有符号&,则需改成”&”或’&’,不然会报错。

  (2)代码的演示

  本次演示的目的就是使用scrapy让百度打印一句话,进而熟悉scrapy的基本使用。如下图,创建文件夹“爬虫的scrapy”。
在这里插入图片描述
  如下图所示,找到新建的文件夹,在命令提示符窗口中将路径切换到这个文件夹。
在这里插入图片描述
在这里插入图片描述
  输入命令“scrapy startproject scrapy_baidu_091”来创建一个名为“scrapy_baidu_091”的项目。可以到PyCharm中去查看是否有对应的项目文件。
在这里插入图片描述
在这里插入图片描述
  再在项目文件夹里创建一个test文件,用来记笔记。然后如下所示,将本次演示的思路进行记录。(其实这个test里面记的笔记是随着程序的编写而记录的,但是本人直接放在此处,以便对整个演示有个指导作用。)
在这里插入图片描述

1. 创建爬虫的项目
    scrapy startproject 项目名字
    注意:项目的名字不允许使用数字开头   也不能包含中文
2. 创建爬虫文件
    要在spiders文件夹中去创建爬虫文件

    进入spiders文件夹:cd 项目的名字\项目的名字\spiders,
    - 本次演示使用的命令为    cd scrapy_baidu_091\scrapy_baidu_091\spiders

    创建爬虫文件
    scrapy genspider 爬虫的名字 要爬取的网页
    eg:scrapy genspider baidu http://www.baidu.com
3. 运行爬虫代码
    scrapy crawl 爬虫的名字
    eg:scrapy crawl baidu
   注:在运行爬虫程序时,需注释掉文件“setting.py”中的“ROBOTSTXT_OBEY = True,
       即不遵守君子协议

在这里插入图片描述
  然后使用命令“cd scrapy_baidu_091\scrapy_baidu_091\spiders”切换到文件夹spiders下,使用命令“scrapy genspider baidu http://www.baidu.com”创建爬虫文件(即“baidu.py”)。
在这里插入图片描述
在这里插入图片描述
  需要知道的是,爬虫的名字一般用于运行爬虫的时候使用的值。
在这里插入图片描述
  如下,对文件“baidu.py”进行编程,然后再在“命令提示符”窗口中输入“scrapy crawl baidu”运行爬虫代码,发现并没有"苍茫的天涯是我的爱"。说明存在反爬手段。

import scrapy


class BaiduSpider(scrapy.Spider):
    # 爬虫的名字     用于运行爬虫的时候使用的值
    name = "baidu"
    # 允许访问的域名
    allowed_domains = ["www.baidu.com"]

    # 起始的url地址     指的是第一次要访问的域名
    # start_urls
    start_urls = ["http://www.baidu.com"]

    # 下面是执行start_urls之后执行的的方法  方法中的response就是返回的那个对象,
    # 相当于    response = urllib.request.uropen()
    #          response = requests.get()

    def parse(self, response):
        print("苍茫的天涯是我的爱")

在这里插入图片描述
  第一个需要解决的是所谓的君子协议,故去文件“setting.py”中注释掉图中所示的代码,即不遵守该协议。(注:scrapy一看就是爬虫程序,理论上得遵守君子协议。但有时仅仅是为了爬取网页上公开的不涉及隐私的、且不会对网站造成任何危害的、不用作商业用途、不损害他人利益、合理合法的使用,一般也没人管,也不会出现问题。)
在这里插入图片描述在这里插入图片描述
  然后再次运行程序,发现“苍茫的天涯是我的爱”已经成功被打印。
在这里插入图片描述
在这里插入图片描述

  3. scrapy之58同城项目结构和基本方法(注:58同城的数据不是公开数据,不能爬取;本次代码也爬取不到相应的数据)

  (1)scrapy项目的组成

在这里插入图片描述

项目名字
    项目名字
        spiders文件夹(存储的是爬虫文件)
            init
            自定义的爬虫文件    核心功能文件  ********
    init
    items           定义数据结构的地方 即爬取的数据都包含哪些
    middlewares     称为中间件   用来设置代理机制
    pipelines        称为管道     用来处理下载的数据
    settings         称为配置文件  robots协议、UA定义的地方

  (2)scrapy爬虫文件的组成以及响应response的属性和方法

在这里插入图片描述

response.text            获取的是响应的字符串
response.body            获取的是二进制数据
response.xpath           可以直接是xpath方法来解析response中的内容
response.extract()       提取seletor对象的data属性值
response.extract_first() 提取的seletor列表的第一个数据

  (3)代码演示

  本次将通过58同城(“https://cn.58.com/”)来介绍response的属性和方法。如下图,打开58同城,搜索前端开发。
在这里插入图片描述
  然后寻找该网页的接口。打开检查,点击网络,清空一下接口,再刷新,很容易就找到了接口。
在这里插入图片描述
  然后去命令提示符创建项目,其实PyCharm终端也可以,本次以终端进行演示。如下图所示,成功创建名为“scrapy_58tc_092”的项目(命令依次为“cd 爬虫的scrapy”、“scrapy startproject scrapy_58tc_092”)。
在这里插入图片描述
  接着复制接口的请求地址,再在PyCharm的终端中进入文件夹“spiders”(命令为“cd .\scrapy_58tc_092\scrapy_58tc_092\spiders\”),再使用命令“scrapy genspider tc 接口请求的地址”创建爬虫文件。(注意:对于请求的地址,如果含有符号&,则需改成”&”或’&’,不然会报错)
在这里插入图片描述
在这里插入图片描述
  如下图,注释掉遵守君子协议(即图中所示代码)。
在这里插入图片描述
  然后回到爬虫文件,然后如下图所示修改一句代码,运行一下代码文件(指令为“scrapy crawl tc”),验证是否能够成功运行。
在这里插入图片描述
在这里插入图片描述
  然后创建一个名为“test”的文件,用来说明scrapy项目的结构以及response的属性和方法,具体如下。(所记内容应该随着演示的进度边做边记录,但为了起指导作用,个人直接听完了然后再来写的笔记)
在这里插入图片描述

1. scrapy项目的结构
    项目名字
        项目名字
            spiders文件夹(存储的是爬虫文件)
                init
                自定义的爬虫文件    核心功能文件  ********
        init
        items           定义数据结构的地方 即爬取的数据都包含哪些
        middlewares     称为中间件   用来设置代理机制
        pipelines       称为管道     用来处理下载的数据
        settings        称为配置文件  robots协议、UA定义的地方

2. response的属性和方法
    response.text            获取的是响应的字符串
    response.body            获取的是二进制数据
    response.xpath           可以直接是xpath方法来解析response中的内容
    response.extract()       提取seletor对象的data属性值
    response.extract_first() 提取的seletor列表的第一个数据

在这里插入图片描述
  然后爬虫文件“tc.py”中进行如下编程运行(运行指令“scrapy crawl tc”),验证是否能获取网页源码。发现网页需要进行58同城的验证。

import scrapy


class TcSpider(scrapy.Spider):
    name = "tc"
    allowed_domains = ["cn.58.com"]
    start_urls = [
        "https://cn.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpoli-cy=uuid_TNcWRNaySTeW63QGr4FnmMaRrMFXfR6e%2Cclassify_B&search_uuid=TNcWRNaySTeW63QGr4FnmMaRrMFXfR6e&search_type=history"]

    def parse(self, response):
        content = response.text  # 获取网页源码
        print('=================================')  # 打印此行,便于寻找代码的执行结果
        print(content)

在这里插入图片描述
在这里插入图片描述
  试了一会不会获取,想要研究的自己去搞。而且去网上查了下,还有人因为爬取58同城的数据而犯法的,吓得赶紧上网查了查关于爬虫的法律法规。
在这里插入图片描述
  下面的话仅为个人观点:由上图可见单纯的抓取公开数据、仅仅违背robots君子协议都不是违法行为。相反,爬虫技术的发展在一定程度上促进了反爬技术的发展。另外,58同城那些数据,确实属于他们的商业信息,不属于公开信息,不应该被随便爬取。不得不说的是,58同城的一些数据通过鼠标点击就能查看到,如果58同城如果没有设立反爬机制,让爬虫轻松爬取到了信息,那样的话自身也有一定责任,信息保护不到位,未成功让爬虫行为人知道这个不是公开信息,不应该爬取58同城的信息。另外,爬虫行为人也应当思考,58同城是靠一些数据信息营业的,不应该去获取他们的数据。还有那几个违法的过分了,绕开反爬机制来爬取非法数据就存在问题了,还用去盈利,错上加错啊。
  因此,我们就不要想着突破58同城,去获取任何数据了。不能突破验证码的代码如下。

import scrapy


class TcSpider(scrapy.Spider):
    name = "tc"
    allowed_domains = ["cn.58.com"]
    start_urls = [
        "https://cn.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpoli-cy=uuid_TNcWRNaySTeW63QGr4FnmMaRrMFXfR6e%2Cclassify_B&search_uuid=TNcWRNaySTeW63QGr4FnmMaRrMFXfR6e&search_type=history"]

    # 请求头
    headers = {
        'User-Agent': 'ozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; Hot Lingo 2.0)'
    }

    def parse(self, response):
        # 1.字符串
        content = response.text  # 获取网页源码
        # 2.二进制数据
        # content = response.body
        # print('=================================')  # 打印此行,便于寻找代码的执行结果
        # print(content)

        span = response.xpath('xpath路径[0]')
        print('=================================')  # 打印此行,便于寻找代码的执行结果
        print(span.extract())

  4. 汽车之家scrapy工作原理

  (1)scrapy架构组成

在这里插入图片描述

  (2)scrapy的工作原理

在这里插入图片描述
  scrapy的工作原理如上图所示,观察绿色的箭头、红色的箭头回路后发现,爬虫spiders先发送一个url给引擎,引擎再将这个url送给调度器。之后,调度器就会生成一个请求对象并发送给引擎,引擎再将这个请求送给下载器,下载器再去向互联网下载数据,并将数据送回引擎,引擎再将数据送给spiders,这个数据就是scrapy爬虫文件中的response,然后spiders再根据需要使用xpath路径来解析数据得到一个解析结果。如果这个解析结果是url,它就会将刚刚的过程再执行一遍;如果这个解析结果是数据,它就被管道下载并保存了。

  (3)代码演示

  本次将演示如何获取汽车之家中,爬取我们感兴趣的数据,这里具体爬取了热门宝马汽车的名字和价格。
  如下图,搜索“汽车之家”(其官网链接为汽车之家),搜索“宝马 热门车”,进入宝马热门车的页面。然后打开检查,点击网络,刷新页面,找到页面的接口。然后复制该接口的请求地址。
在这里插入图片描述
在这里插入图片描述
  使用指令进入文件夹“爬虫的scrapy”(“cd .\爬虫的scrapy\”),创建名为“scrapy_carhome_093”的项目(“scrapy startproject scrapy_carhome_093”)。
在这里插入图片描述
  如下图所示,进入文件夹spiders(“cd .\scrapy_carhome_093\scrapy_carhome_093\spiders\”)中创建爬虫文件“car.py”(“scrapy genspider car 接口的请求地址”)。
在这里插入图片描述
  如下图所示,仅修改一句代码,验证在该网站上能否执行程序。
在这里插入图片描述
在这里插入图片描述
  如下图所示,找到各个图片的名字的xpath路径,然后再复制(记得加上“/text()”)。
在这里插入图片描述
在这里插入图片描述
  然后编写代码,验证获取的数据是否包含车名。然后思考怎么获取车名的数据。

import scrapy


class CarSpider(scrapy.Spider):
    name = "car"
    allowed_domains = ["car.autohome.com.cn"]
    start_urls = ["https://car.autohome.com.cn/price/brand-15.html"]

    def parse(self, response):
        name_list = response.xpath('//div[@class="list-cont"]/div/div[2]/div[1]/a/text()')

        for name in name_list:
            print(name)

在这里插入图片描述
在这里插入图片描述
  此时我们想到获取标签的属性值需使用extract,故继续编写代码,获取车名。
在这里插入图片描述
在这里插入图片描述
  如果我们对车的价格比较感兴趣,可与获取车名的方法一样,找到它们的xpath路径,然后继续编程,获取到对应的数据。
在这里插入图片描述

import scrapy


class CarSpider(scrapy.Spider):
    name = "car"
    allowed_domains = ["car.autohome.com.cn"]
    start_urls = ["https://car.autohome.com.cn/price/brand-15.html"]

    def parse(self, response):
        name_list = response.xpath('//div[@class="list-cont"]/div/div[2]/div[1]/a/text()')
        price_list = response.xpath('//*[@id="brandtab-1"]/div/div/div[2]/div[2]/div[2]/div[1]/span/span/text()')

        for i in range(len(name_list)):
            name = name_list[i].extract()
            price = price_list[i].extract()
            print(name, price)

在这里插入图片描述
在这里插入图片描述

  5.调试工具scrapy shell

  (1)什么是scrapy shell

在这里插入图片描述

  (2)安装ipython

在这里插入图片描述
  具体安装步骤如下:使用快捷键Win+R打开运行窗口,输入cmd并按Enter键打开命令提示符窗口。
在这里插入图片描述
  在命令提示符窗口中将目录切换到scripts文件夹中,再使用命令“pip install ipython -i https://pypi.mirrors.ustc.edu.cn/simple/”安装。
在这里插入图片描述

  (3)ipython的使用方法

在这里插入图片描述

# 进入到scrapy shell的终端    直接在windows的终端中输入scrapy shell 域名
# 如果想看到一些高亮 或者 自动补全 那么可以安装ipython 安装命令:pip install ipython

# scrapy shellI www.baidu.com

  如下图所示,在终端中使用scrapy shell进入百度,然后就会返回一堆对象。
在这里插入图片描述
在这里插入图片描述
  之后就可以按照scrapy的语法正常使用了,可见scrapy shell对于调试、获取复杂网页的数据来说,十分便利。
在这里插入图片描述
在这里插入图片描述

  6. scrapy之当当网爬取数据(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)

  (1)yied

在这里插入图片描述

  (2)本节的演示

  本次将演示如何下载当当网中的10页数据。(原视频讲解了如何爬取某个分类的所以有数据,我们就是学习使用而已,爬两页就够了,别人维护网站也不容易。再次强调,爬取数据仅供学习使用,千万别商用。)
如下图,进入到当当网(“http://www.dangdang.com/”)的“爱情/情感”的电子书的网页中。
在这里插入图片描述
在这里插入图片描述
  如下图,使用命令“scrapy startproject scrapy_dangdang_095”创建项目文件。
在这里插入图片描述
  再使用指令“cd scrapy_dangdang_095/scrapy_dangdang_095/spiders”进入文件夹“spiders”中,使用指令“scrapy genspider dang 域名”创建爬虫文件“dang.py”(其中域名为刚刚复制的网址,另外,网址中含有&,需要变成‘&’或”&”)。
在这里插入图片描述
在这里插入图片描述
  然后尝试打印一行数据,判断是否含有反爬手段。结果发现没有。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class ScrapyDangdang095Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # 数据结构,通俗地说就是你要下载的数据都有什么
    # 图片
    src = scrapy.Field()
    # 名字
    name = scrapy.Field()
    # 价格
    price = scrapy.Field()

在这里插入图片描述
在这里插入图片描述
  然后去文件“items.py”中定义本次演示的数据结构。数据结构,通俗地说就是你要下载的数据都有什么。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class ScrapyDangdang095Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # 数据结构,通俗地说就是你要下载的数据都有什么
    # 图片
    src = scrapy.Field()
    # 名字
    name = scrapy.Field()
    # 价格
    price = scrapy.Field()

在这里插入图片描述
  如下图,寻找到图片、书名、价格的xpath路径,然后复制到PyCharm中。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  观察这几个数据的xpath路径,发现都在一个a标签下。于是继续编写程序。
在这里插入图片描述
  编写程序并执行,猜测当当网可能加入了君子协议(robots协议),得去注释君子协议后在来运行,还是没有返回数据。

import scrapy


class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["e.dangdang.com"]
    start_urls = ["http://e.dangdang.com/classification_list_page.html?category=AQQG&dimension=dd_sale&order=0"]

    def parse(self, response):
        # pipelines     管道用于下载数据
        # items         定义数据结构

        # 数据的xpath路径
        # src="//div[@id="book_list"]/a/span/img[2]/@src"
        # alt="//div[@id="book_list"]/a/span/img[2]/@alt"
        # price"//div[@id="book_list"]/a/div/div[4]/span[@class="now"]/text()"
        # 所有的selector的对象 都可以再次调用xpath方法

        a_list = response.xpath('//div[@id="book_list"]/a')
        print(a_list)

        for a in a_list:
            src = a.xpath('.//span/img[2]/@src').extract_first()  # 注意“.”表示当前路径下的意思,"./"不能省
            name = a.xpath('.//span/img[2]/@alt').extract()
            price = a.xpath('.//div/div[4]/span[@class="now"]/text()').extract().strip()
            print(src, name, price)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  暂时不会了,于是听完视频后发现代码不用变(本次没有发现懒加载导致数据的xpath路径不一样的问题)。注意,在第九节中该问题已经被解决。

  7.scrapy_当当网管道封装(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)

  紧接着上一讲的继续。如下代码所示,将爬取的数据交给管道。

import scrapy
from ..items import ScrapyDangdang095Item


class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["e.dangdang.com"]
    start_urls = ["http://e.dangdang.com/classification_list_page.html?category=AQQG&dimension=dd_sale&order=0"]

    def parse(self, response):
        # pipelines     管道用于下载数据
        # items         定义数据结构

        # 数据的xpath路径
        # src="//div[@id="book_list"]/a/span/img[2]/@src"
        # alt="//div[@id="book_list"]/a/span/img[2]/@alt"
        # price"//div[@id="book_list"]/a/div/div[4]/span[@class="now"]/text()"
        # 所有的selector的对象 都可以再次调用xpath方法
        print('==========================================')

        a_list = response.xpath('//div[@id="book_list"]/a')
        print(a_list)

        for a in a_list:
            src = a.xpath('.//span/img[2]/@src').extract_first()  # 注意“.”表示当前路径下的意思,"./"不能省
            name = a.xpath('.//span/img[2]/@alt').extract()
            price = a.xpath('.//div/div[4]/span[@class="now"]/text()').extract().strip()
            # print(src, name, price)  测试代码,验证数据是否获取成功

            book = ScrapyDangdang095Item(src=src, name=name, price=price)

            # 需要将book(即ScrapyDangdang095Item对象)交给pipeline下载
            yield book  # 获取一个book就将book交给管道pipeline

在这里插入图片描述
  如下图,去文件“settings.py”中开启管道。(注:管道可以有很多个,那么管道是有优先级的。优先级的范围是1-1000,值越小,优先级越高。)
在这里插入图片描述
  然后去管道文件“pipelines.py”中封装管道。

# 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


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


# 如果想使用管道的话 那么必须在settings中开启管道
class ScrapyDangdang095Pipeline:
    # 在爬虫文件开始之前 执行的方法
    def open_spider(self, spider):
        self.fp = open('book.json', 'w', encoding='UTF-8')

    # item就是yield后面的book对象
    def process_item(self, item, spider):
        # 以下这种模式不推荐  因为每传递过来一个对象就打开一次文件  对文件的操作过于频繁
        # 因此定义了方法open_spider()、close_spider()
        # with open('book.json', 'a', encoding="UTF-8") as fp:
        #     # 存在两个坑
        #     # (1)write方法里的内容必须是字符串
        #     # (2)w模式下,每个对象都会打开一次文件  会覆盖之前的内容
        #     #      故改成 a追加模式
        #     fp.write(item)

        self.fp.write(str(item))
        return item

    # 在爬虫文件执行完成之后 执行的方法
    def close_spider(self, spider):
        self.fp.close()

在这里插入图片描述

  8.scrapy_当当网开启多条管道下载(本节获取数据失败,已在第9节成功解决,不想再改动本节内容了)

  紧接着上一节,本节将演示当当网开启多条管道下载,具体为设两条管道,一边下载json数据,一边下载图片。
  创建名为“books”的文件夹用来存储图片。
在这里插入图片描述
  去管道文件“pipelines.py”中定义新的管道类。

# 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


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


# 如果想使用管道的话 那么必须在settings中开启管道
class ScrapyDangdang095Pipeline:
    # 在爬虫文件开始之前 执行的方法
    def open_spider(self, spider):
        self.fp = open('book.json', 'w', encoding='UTF-8')

    # item就是yield后面的book对象
    def process_item(self, item, spider):
        # 以下这种模式不推荐  因为每传递过来一个对象就打开一次文件  对文件的操作过于频繁
        # 因此定义了方法open_spider()、close_spider()
        # with open('book.json', 'a', encoding="UTF-8") as fp:
        #     # 存在两个坑
        #     # (1)write方法里的内容必须是字符串
        #     # (2)w模式下,每个对象都会打开一次文件  会覆盖之前的内容
        #     #      故改成 a追加模式
        #     fp.write(item)

        self.fp.write(str(item))
        return item

    # 在爬虫文件执行完成之后 执行的方法
    def close_spider(self, spider):
        self.fp.close()


import urllib.request

# 第二条管道   下载图片
# 多条管道开启  模仿前面的管道进行编写
"""
步骤:(1)定义管道类
     (2)在settings中开启管道

"""
class DangDangDownloadPipeline:
    def process_item(self, item, spider):
        url = 'http:' + item.get('src')
        filename = './books/' + item.get('name') + '.jpg'
        urllib.request.urlretrieve(url=url, filename=filename)

        return item

在这里插入图片描述
  在文件“settings.py”中开启新管道。

ITEM_PIPELINES = {
    # 管道可以有很多个 那么管道是有优先级的 优先级的范围是1-1000 值越小,优先级越高
    "scrapy_dangdang_095.pipelines.ScrapyDangdang095Pipeline": 300,

    # DangDangDownloadPipeline
    "scrapy_dangdang_095.pipelines.DangDangDownloadPipeline": 301,
}

在这里插入图片描述

  9.scrapy_当当网多页下载

  紧接着上一节,本节将演示多页的下载。首先我们需要知道,每一页的爬取的业务逻辑全都是一样的,所以只需要将执行的那个页的请求再次调用parse方法就可以了。
  去观察网络的接口,找到了存储数据的接口,并将接口的请求地址复制到PyCharm中,成功解决前面几节没有返回数据的问题。
在这里插入图片描述
在这里插入图片描述
  然后编写“dang.py”的代码。

import scrapy
from ..items import ScrapyDangdang095Item
import jsonpath
import json


class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["e.dangdang.com"]
    start_urls = [
        "http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&start=0&end=20&category=AQQG&dimension=dd_sale"]

    def parse(self, response):
        # pipelines     管道用于下载数据
        # items         定义数据结构

        print('==========================================')

        # print(response.text) # 发现获取的是json数据
        # with open('网页源码.json','w',encoding='UTF-8') as fp:
        #     fp.write(response.text)

        # 观察数据后直接使用jsonpath进行解析
        obj = json.loads(response.text)
        # 图片地址的列表
        src_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].coverPic')
        # 书名的列表
        name_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].title')
        # 价格的列表
        price_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].salePrice')
        # print(src_list)
        # print(name_list)
        # print(price_list)
        for i in range(len(src_list)):
            src = src_list[i]
            # 替换特殊字符为下划线
            name = name_list[i].strip().replace('/', '_')\
                .replace('\\', '_').replace(':', '_').replace('【','(').replace('】',')')
            price = str(price_list[i])+'元'
            # print(src, name, price)  # 测试代码,验证数据是否获取成功

            book = ScrapyDangdang095Item(src=src, name=name, price=price)

            # 需要将book(即ScrapyDangdang095Item对象)交给pipeline下载
            yield book  # 获取一个book就将book交给管道pipeline

在这里插入图片描述
  修改文件“pipelines.py”的代码,再次运行,发现第6、7、8节的功能都已实现。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  同理,将连续几页接口的请求地址复制到PyCharm中,观察不同页码的请求地址的变化,根据请求地址的不同观察出其中的规律。
在这里插入图片描述
  如下图所示,继续编写文件“dang.py”的代码(在下载10页图片时具体解决的问题:如何让不规范的文件名字变成合法的文件名字、如何处理相同的文件名字,请自行阅读代码进行理解)。

import scrapy
from ..items import ScrapyDangdang095Item
import jsonpath
import json


# import os  # 用于判断哪些文件未成功下载,进而分析原因


class DangSpider(scrapy.Spider):
    name = "dang"
    # 如果是多页下载,allowed_domains的范围需要调整,‘http://’以及更改的部分不能留
    allowed_domains = ["e.dangdang.com"]
    start_urls = [
        "http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&start=0&end=20&category=AQQG&dimension=dd_sale"]

    # 前三页的接口地址
    # http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&start=0&end=20&category=AQQG&dimension=dd_sale
    # http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&start=21&end=41&category=AQQG&dimension=dd_sale
    # http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&start=42&end=62&category=AQQG&dimension=dd_sale

    base_url = 'http://e.dangdang.com/media/api.go?action=mediaCategoryLeaf&promotionType=1&deviceSerial-No=html5&macAddr=html5&channelType=html5&permanentId=20230814120937742356681582820154551&returnType=json&channelId=70000&clientVersionNo=6.8.0&platformSource=DDDS-P&fromPlatform=106&deviceType=pconline&token=&'
    page = 1
    all_name_list = []  # 所有名字的列表,用于判断哪些文件未成功被下载

    def parse(self, response):
        # pipelines     管道用于下载数据
        # items         定义数据结构

        print('==========================================')

        # print(response.text) # 发现获取的是json数据
        # with open('网页源码.json','w',encoding='UTF-8') as fp:
        #     fp.write(response.text)

        # 观察数据后直接使用jsonpath进行解析
        obj = json.loads(response.text)
        # 图片地址的列表
        src_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].coverPic')
        # 书名的列表
        name_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].title')
        # 价格的列表
        price_list = jsonpath.jsonpath(obj, '$.data.saleList.*.mediaList[0].salePrice')
        # print(src_list)
        # print(name_list)
        # print(price_list)
        for i in range(len(src_list)):
            src = src_list[i]
            # 替换特殊字符为下划线
            name = name_list[i].strip().replace('/', '_') \
                .replace('\\', '_').replace(':', '_').replace('【', '(').replace('】', ')') \
                .replace('?', '_').replace('*', '_')
            # 防止出现相同的名字
            name_count = 0
            while name in self.all_name_list:
                name_count += 1
                name = f"{name}_{name_count}"  # 在元素后面添加计数

            self.all_name_list.append(name)
            price = str(price_list[i]) + '元'
            # print(src, name, price)  # 测试代码,验证数据是否获取成功

            book = ScrapyDangdang095Item(src=src, name=name, price=price)

            # 需要将book(即ScrapyDangdang095Item对象)交给pipeline下载
            yield book  # 获取一个book就将book交给管道pipeline

        # 每一页的爬取的业务逻辑全都是一样的,所以只需要将执行的那个页的请求再次调用parse方法就可以了
        if self.page < 10:
            self.page += 1
            url = self.base_url + f"start={(self.page - 1) * 21}&end={self.page * 21 - 1}&category=AQQG&dimension=dd_sale"

            # 怎么调用parse方法
            # scrapy.Request就是scrapy的get请求
            # - url就是请求地址、callback就是需要执行的函数、parse不能加括号
            yield scrapy.Request(url=url, callback=self.parse)

        # # 找到未被下载的图片
        #     print(len(self.all_name_list))
        #     print(self.all_name_list)
        #     for name in self.all_name_list:
        #         if not os.path.exists(f'./books/{name}.jpg'):
        #             print(f"未被下载的图片:{name}.jpg")

在这里插入图片描述
在这里插入图片描述

  10.scrapy_电影天堂多页数据下载

  打开电影天堂(网站链接为电影天堂,其实本网站已不再更新,网站已经更换域名,但为了和视频讲解尽量一致,本次演示所选的还是原来的网站),选择国内电影。然后点击“世界上最爱我的人”,发现该电影对应的封面。本次需求是在“items.py”定义本次的数据结构,然后将标题“世界上最爱我的人”和对应图片的地址定义为一个item对象进行下载,最终得到的数据是含标题和图片地址的json文件。如果还想下载图片,请参考上一节的“pipelines.py”的代码。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  如下图,创建一个名为“scrapy_movie_099”的项目(“scrapy startproject scrapy_movie_099”)。
在这里插入图片描述
  如下图所示,寻找含有电影名字的接口,并复制其请求地址。
在这里插入图片描述
在这里插入图片描述
  然后进入文件夹spiders中(“cd scrapy_movie_099\scrapy_movie_099\spiders”),创建爬虫文件“mv.py”(“scrapy genspider mv 域名”)。
在这里插入图片描述
  然后看看程序是否能正常打印,如果能正常打印则说明不存在反爬。
在这里插入图片描述
在这里插入图片描述
  先去“items.py”中定义本次下载的数据结构。

# 电影的名字
name = scrapy.Field()
# 电影的图片的请求地址
src = scrapy.Field()

在这里插入图片描述
  如下图,找到了电影题目的位置和第二页的地址。
在这里插入图片描述
在这里插入图片描述
  如下图,找到电影电影题目和第二页的地址的xpath路径。
在这里插入图片描述
在这里插入图片描述
  后面发现实际的xpath路径和浏览器里寻找的不一致,故将网页源码写到文件中,根据网页源码手动编写xpath路径,然后运行程序,发现能够获取到电影名字以及第二页的地址。

import scrapy


class MvSpider(scrapy.Spider):
    name = "mv"
    allowed_domains = ["www.dytt.to"]
    start_urls = ["https://www.dytt.to/html/gndy/china/index.html"]

    def parse(self, response):
        # 要第一页的名字 和 第二页的图片的地址
        # 对应的xpath路径
        # '//table/tr[2]/td[2]/b/a[2]/text()'
        # '//table/tr[2]/td[2]/b/a[2]/@href'
        # 将网页源码写进一个文件中
        with open('mv.html', 'w', encoding='UTF-8') as fp:
            fp.write(response.text)

        # a_list:含电影名字以及第二页的地址的标签的列表
        a_list = response.xpath('//table/tr[2]/td[2]/b/a[2]')
        for a in a_list:
            name = a.xpath('./text()').extract_first()
            href = a.xpath('./@href').extract_first()
            print(name, href)  # 测试代码,验证是否成功获取电影名字以及第二页的地址

在这里插入图片描述
在这里插入图片描述
  经观察,实际的链接比herf多“https://www.dytt.to/”。
在这里插入图片描述
  与前面同理,找到第二页图片的请求地址的xpath路径,后面实际上运行后与浏览器找的不一样,是把实际的网页源码写成文件找的,此处是span标签和浏览器中不一样(截图已省)。
在这里插入图片描述
  编写“mv.py”代码(注意学会:将name传到meta,以便在定义到的parse方法中收到该参数),在“setting.py”中打开管道,在“pipelines.py”中封装管道,然后运行。

import scrapy
from ..items import ScrapyMovie099Item


class MvSpider(scrapy.Spider):
    name = "mv"
    # 范围可以设大一点
    allowed_domains = ["www.dytt.to"]
    start_urls = ["https://www.dytt.to/html/gndy/china/index.html"]

    def parse(self, response):
        # 要第一页的名字 和 第二页的图片的地址
        # 对应的xpath路径
        # '//table/tr[2]/td[2]/b/a[2]/text()'
        # '//table/tr[2]/td[2]/b/a[2]/@href'

        # # 将网页源码写进一个文件中
        # with open('mv.html', 'w', encoding='UTF-8') as fp:
        #     fp.write(response.text)

        # a_list:含电影名字以及第二页的地址的标签的列表
        a_list = response.xpath('//table/tr[2]/td[2]/b/a[2]')
        for a in a_list:
            # 获取第一页的name和要点击的链接href
            name = a.xpath('./text()').extract_first()
            href = a.xpath('./@href').extract_first()
            # print(name, href)  # 测试代码,验证是否成功获取电影名字以及第二页的地址

            # 第二页的地址
            # 实际的链接比herf多“https://www.dytt.to/”
            url = 'https://www.dytt.to/' + href
            # print(name, url)  # 测试代码,验证是否是电影名字以及第二页的地址

            # 对第二页的链接发起访问  将name传到meta,以便在方法parse_second中收到该参数
            yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})

    def parse_second(self, response):
        # print('1234567890')  # 验证是否会执行本方法

        # # 将网页源码写进一个文件中
        # with open('mv_picture.html', 'w', encoding='UTF-8') as fp:
        #     fp.write(response.text)

        # 第二页图片的请求地址
        src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
        # print(src)  # 测试代码,验证是否获取到第二页图片的请求地址

        # 接收到请求的meta参数的值   实际就是电影名字
        name = response.meta['name']

        movie = ScrapyMovie099Item(src=src, name=name)
        # 将movie返回给管道
        yield movie

在这里插入图片描述
在这里插入图片描述

# 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


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


class ScrapyMovie099Pipeline:
    # 打开管道
    def open_spider(self, spider):
        self.fp = open('movie.json', 'w', encoding='UTF-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))
        return item

    # 关闭管道
    def close_spider(self,spider):
        self.fp.close()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  11. scrapy_链接提取器CrawlSpider的使用(含MySql、pymysql的使用)

  本节将使用CrawlSpider简单地爬取数据,熟悉CrawlSpider的链接提取器的语法,然后下下一节将使用MySql、pymysql将数据放入数据库中。

  (1)MySQL的安装和初级使用

  关于MySQL的安装和初级使用,请参考本人的笔记:第二阶段-第二章 SQL入门和实战

  (2)CrawlSpider的作用

在这里插入图片描述
  比如,我们可以设定一个规则,然后把当前页面所有符合这个规则的链接提取出来,然后对这些链接进行解析就可以了。
在这里插入图片描述

  (3)CrawlSpider的使用方法

在这里插入图片描述
  对于链接提取器而言,常用的是正则表达式、xpath、css,即allow=()、restrict_xpaths =()、restrict_css =()。
在这里插入图片描述

  (4)代码演示

  本次将以读书网进行演示,使用正则表达式和xpath来提取页码的链接。如下图,打开读书网,选择“当代小说”,然后在检查中找到页码的链接。然后,复制读书网的当代小说的第一页的链接。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  如下图所示,使用scrapy shell进入读书网的当代小说的第一页的页面,输入“from scrapy.linkextractors import LinkExtractor”导入链接提取器。
在这里插入图片描述
  首先使用正则表达式提取页码的链接(“link = LinkExtrac-tor(allow=r’/book/1188_\d+.html’)”),“\d”表示一个数字,“\d+”表示可以有一到多个数字,然后打印一下验证正则表达式是否书写正确(“link.extract_links(response)”)。
在这里插入图片描述
  然后再使用xpath路径提取页码的链接(“link1 = LinkExtrac-tor(restrict_xpaths=r’//div[@class=“pages”]/a’)”,别加“@href”,否则提取不了),然后打印一下验证正则表达式是否书写正确(“link1.extract_links(response)”)。
在这里插入图片描述
在这里插入图片描述

  12.scrapy_crawlspider读书网获取图片的封面地址和名字

  紧跟着上一节,本节继续。

  (1)CrawlSpider的使用步骤

在这里插入图片描述

  (2)代码演示

  本节紧接着上一节,使用CrawlSpider爬取读书网中当代小说的书名和书的封面的地址,下一节使用MySql、pymysql将数据放入数据库中。
  首先,创建一个名为“scrapy_readbook_101”的项目(“scrapy startproject scrapy_readbook_101”)。
在这里插入图片描述
  先去复制读书网当代小说第一页的地址,然后回到PyCharm终端,进入文件夹“spiders”(“cd scrapy_readbook_101\scrapy_readbook_101\spiders”),创建爬虫文件”read.py”(指令为“scrapy genspider -t crawl read 域名”,与之前创建的scrapy爬虫文件的指令有所不同)。
在这里插入图片描述
在这里插入图片描述
  创建一个名为“test”的文件,用来记录本次案例的流程。
在这里插入图片描述

1. 创建项目 scrapy startproject 项目的名字
2. 跳转到spiders文件夹的目录下
   cd 项目名字\项目名字\spiders
3. 创建爬虫文件
   scrapy genspider -t crawl 爬虫文件的名字 爬取的域名

在这里插入图片描述
  如下图,根据页码的链接的变化规律在代码相应的地方编写正则表达式(注:在正则表达式中,“.”是通配符,故特指点需要使用反斜杠来转义,即“.”)。
在这里插入图片描述
  然后去“items.py”中定义本次下载的数据的结构。

# 书名
name = scrapy.Field()
# 书的封面的地址
src = scrapy.Field()

在这里插入图片描述
  然后去寻找书名和封面地址的xpath路径,看到“data-original”就想到懒加载,即封面地址是属性“data-original”里的内容。发现有本书由于缺少封面,导致data-original获取的内容少一项,少的那一项需要通过属性src来获取标有读书网的图片的地址。
在这里插入图片描述
在这里插入图片描述
  如下编写爬虫文件“read.py”的代码。

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import ScrapyReadbook101Item

class ReadSpider(CrawlSpider):
    name = "read"
    # 范围设大点,得包含其他页
    allowed_domains = ["www.dushu.com"]
    start_urls = ["https://www.dushu.com/book/1188.html"]

    rules = (Rule(
        LinkExtractor(allow=r"/book/1188_\d+\.html"),
        callback="parse_item",
        follow=False),)

    def parse_item(self, response):
        # 书名和封面的xpath路径
        # //li/div/div/a/img/@alt
        # //li/div/div/a/img/@data-original
        # 发现有本书由于缺少封面,导致data-original获取的内容少一项,
        # 少的那一项需要通过属性src来获取标有读书网的图片的地址。
        img_list = response.xpath('//li/div/div/a/img')
        for img in img_list:
            name = img.xpath('./@alt').extract_first()
            src = img.xpath('./@data-original').extract_first()
            if not src:
                src = img.xpath('./@src').extract_first()

            # print(name, src)  # 测试代码,验证是否拿到书名和封面链接

            book = ScrapyReadbook101Item(name=name, src=src)
            yield book

  如下去文件“pipelines.py”封装管道。

# 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


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


class ScrapyReadbook101Pipeline:
    def open_spider(self, spider):
        self.fp = open('book.json', 'w', encoding='UTF-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))
        return item

    def close_spider(self, spider):
        self.fp.close()

在这里插入图片描述
  去文件“setting.py”中打开管道。
在这里插入图片描述
  运行代码,发现数据不够。
在这里插入图片描述
  由于520-480=40,猜测少了一页数据。注意此处有一个坑,首页并不在我们所设的正则表达式的规则里。
在这里插入图片描述
  尝试将链接“https://www.dushu.com/book/1188.html”改成“https://www.dushu.com/book/1188_1.html”后发现这还是第一页,故去修改“read.py”的起始链接,然后再运行(“scrapy crawl read”),去文件“book.json”发现数据不再缺少。
在这里插入图片描述

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import ScrapyReadbook101Item

class ReadSpider(CrawlSpider):
    name = "read"
    # 范围设大点,得包含其他页
    allowed_domains = ["www.dushu.com"]
    start_urls = ["https://www.dushu.com/book/1188_1.html"]

    rules = (Rule(
        LinkExtractor(allow=r"/book/1188_\d+\.html"),
        callback="parse_item",
        follow=False),)

    def parse_item(self, response):
        # 书名和封面的xpath路径
        # //li/div/div/a/img/@alt
        # //li/div/div/a/img/@data-original
        # 发现有本书由于缺少封面,导致data-original获取的内容少一项,
        # 少的那一项需要通过属性src来获取标有读书网的图片的地址。
        img_list = response.xpath('//li/div/div/a/img')
        for img in img_list:
            name = img.xpath('./@alt').extract_first()
            src = img.xpath('./@data-original').extract_first()
            if not src:
                src = img.xpath('./@src').extract_first()

            # print(name, src)  # 测试代码,验证是否拿到书名和封面链接

            book = ScrapyReadbook101Item(name=name, src=src)
            yield book

在这里插入图片描述

  13.scrapy_读书网数据入库和链接跟进(失败,卡在最后的“由于日标计算机积极拒绝”,没有系统学过MySQL,卡住了)

  紧跟着上一节,本节继续。接下来我们需要将爬取的数据存储到数据库中。为了模拟干活时使用的数据库,本次使用了VMware上的虚拟机Ubuntu。

  (1)准备工作(安装Ubuntu、在Ubuntu上安装mysql中途含出现的两个问题的解决办法、Windows上安装pymysql)

  安装带有Ubuntu的VMware虚拟机,而且Ubuntu中还需要安装mysql,在Windows上安装pymysql。
  至于如何安装VMware、如何在VMware上安装Ubuntu,请参考本人的笔记“第一章 初识Linux(含VMware安装Ubuntu、CentOS、Windows、快照)”进行安装。
  至于MySql的使用方法,对与初级使用而言,本人的CSDN笔记足以应对:第二阶段-第二章 SQL入门和实战。
  至于如何在Ubuntu上安装mysql,本人参考如下连接进行安装的:Ubuntu下安装MySQL数据库,具体步骤如下:
  在FinalShell(直接在VMware中的Ubuntu界面也是一样)输入命令更新一下软件包,然后安装MySQL数据库。(视频里能正常安装,本人的却出现了问题)

sudo apt update    # 更新软件包
sudo apt install mysql-server    # 安装MySQL数据库

在这里插入图片描述在这里插入图片描述
  然后如下图所示,输入一堆命令后成功解决该问题。(这个报错需要根据提示解决。起初没注意看,直接网上查,查到的一堆博客没有一个能解决该问题,后面才看到这句提示,大意了)

sudo apt install mysql-server    # 安装MySQL数据库
apt --fix-broken install
sudo su       # 进入管理员模式
exit          # 如果在root状态,退出管理员模式

在这里插入图片描述
在这里插入图片描述
  然后就是配置安全设置。

sudo mysql_secure_installation    # 配置安全设置

在这里插入图片描述
在这里插入图片描述
  然后检查mysql server是否正在运行(如果出现“lines 1-14/14 (END”,需按Ctr+C结束)。

systemctl status mysql.service    # 检查mysql server是否正在运行

在这里插入图片描述
  连接mysql时报错“ERROR 1045 (28000): Access denied for user ‘-root’@‘localhost’ (using password: YES)”或者“ERROR 1698 (28000): Access denied for user ‘root’@‘localhost’”,找了半天终于按照链接mysqlERROR1698(28000):Access denied for user root@localhost错误解决方法中的STEP1成功解决问题,如下一堆图所示。到此,Ubuntu上已经成功安装pymysql。

sudo mysql -u -root -p    # 连接mysql,sudo是使用root权限的意思,下图中有一处没加sudo一样可以连接mysql
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf    # 编辑文件
service mysql restart    # 重启mysql
show schemas;      # 在mysql里输入表示查询自带的数据库
exit       # 在mysql里输入表示退出mysql

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  至于如何在Windows上安装pymysql,如下图所示,打开命令提示符,然后输入一堆指令完成安装(本人之前装过,就直接截的视频的图)。

cd python的安装目录/Scripts      # 进入python的库文件夹
pip install pymysql  # 安装库pymysql  如果安装太慢,在该条指令后面加上“-i 镜像源的网址”

在这里插入图片描述
在这里插入图片描述

  (2)pymysql的使用步骤

# 具体如何使用请看演示
pip install pymysql  # 安装pymysql
self.conn=pymysql.connect(host, port, user, password, db, charset) # 连接mysql
self.cursor=self.conn.cursor()
cursor.execute()   # 执行mysql代码

  (3)本次的演示(失败,卡在最后的“由于日标计算机积极拒绝”)

  本次需要使用Ubuntu去数据库中创建一个和上一节爬取到的数据的结构一样的表,然后将爬取的数据插入表中。
  双击打开VMware,然后选择Ubuntu进行登录。
在这里插入图片描述
在这里插入图片描述
  打开终端,连接mysql,创建数据库spider01。

sudo mysql -u -root -p    # 连接mysql
create database spider01 charset utf8;    # 创建数据库spider01
show schemas;      # 在mysql里输入表示查询自带的数据库

在这里插入图片描述
在这里插入图片描述
  然后使用刚刚创建的数据库,创建一张表。

use spider01;       # 使用数据库spider01
create table book(id int primary key auto_increment,name varchar(128),src varchar(128));     # 在当前使用的库中创建一张表book,包含id、name和src三列,id列将作为自增的主键,其他两列字符长度最大均为128
select * from book;     # 查询表book的内容

在这里插入图片描述
  表创建成功后,接下来需要将爬取的数据插入这个表中。首先,打开新的终端来查询Ubuntu的ip地址。

ip address show     # 查询ip

在这里插入图片描述
  打开PyCharm,在文件“setting.py”中配置几个参数,即随便找个位置输入下面几行代码(参数请根据自己的情况进行修改)。

DB_HOST = '192.168.13.129'   # 根据刚刚查询的ip设置主机的ip地址
DB_PORT = 3306           # 端口号是一个整数
DB_USER = 'jane'          # Ubuntu的用户名
DB_PASSWORD = '12345'   # Ubuntu的密码
DB_NAME = 'spider01'      # 数据库的名字
DB_CHARSET = 'UTF-8'    # 指定字符集

在这里插入图片描述
    再去“pipelines.py”中造一个管道,以便传到Ubuntu。

# 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


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


class ScrapyReadbook101Pipeline:
    def open_spider(self, spider):
        self.fp = open('book.json', 'w', encoding='UTF-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))
        return item

    def close_spider(self, spider):
        self.fp.close()


# 导入setting文件
from scrapy.utils.project import get_project_settings
import pymysql


# 将数据传输给Ubuntu的管道
class MysqlPipeline:
    # 连接MySql
    def open_spider(self, spider):
        settings = get_project_settings()  # 加载setting文件
        self.host = settings['DB_HOST']
        self.port = settings['DB_PORT']
        self.user = settings['DB_USER']
        self.password = settings['DB_PASSWORD']
        self.name = settings['DB_NAME']
        self.charset = settings['DB_CHARSET']

        # 调用coonnect()连接musql
        self.coonnect()

    def coonnect(self):
        """
        连接MySql的函数
        """
        self.conn = pymysql.connect(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            db=self.name,
            charset=self.charset
        )
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        # MySQL语句,将数据传入表book中
        sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'], item['src'])
        self.cursor.execute(sql)  # 执行mysql语句
        self.conn.commit() # 确认提交

        return item

    # 断开MySql的连接
    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()

  在文件“setting.py”中打开管道。

    # MysqlPipeline
    "scrapy_readbook_101.pipelines.MysqlPipeline": 301

在这里插入图片描述
  运行程序,发现有“encoding”报错。

cd 爬虫的scrapy
cd scrapy_readbook_101\scrapy_readbook_101\spiders
scrapy crawl read

在这里插入图片描述
在这里插入图片描述
  然后进行如下修改,另外为了爬取所有所有数据(页数不局限于13页),故去修改“read.py”中的一个参数,然后再运行程序。

scrapy crawl read

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  查了一堆还是不会解决这个问题,希望有成功解决的兄弟分享一下方法。
  比如下面的方法连个截图都没有,真抽象,没有解决问题。按照“https://blog.csdn.net/wangshuminjava/article/details/79310086”的提示,去ping一下Ubuntu的ip,telnet一下Ubuntu的端口(如果提示’telnet’ 不是内部或外部命令,请参考“https://blog.csdn.net/qq_36292543/article/details/119645130”去打开telnet)。

ping 192.168.13.129    # 验证是否能连通Ubuntu的ip
telnet 192.168.13.129 3306  # 验证是否能使用3306端口连接到Ubuntu

在这里插入图片描述
  修改防火墙允许3306也不行(方法来源于“https://blog.csdn.net/qq_43567345/article/details/105323795”)。改权限grant还失效,好多给出的解决办法都是针对的5.7,新版的较少。就算有,没有系统学过MySQL的东西暂时看不明白。
已放弃,一时半会是解决不了的。

  注:由于本节内容因为卡在最后一步不能正常运行,需要将本节新添的代码注释掉。

  14. scrapy_日志信息以及日志级别

  (1)日志信息的定义、等级、如何设置日志

  如下图所示,运行第12节的代码后会出现很多信息,这些都是scrapy的日志信息。对我们而言,不需要看浏览这么多信息。
在这里插入图片描述
在这里插入图片描述

  (2)代码演示

  如下图,创建项目和爬虫文件。

cd 爬虫的scrapy      # 进入文件夹“爬虫的scrapy”
scrapy startproject scrapy_log_103     # 创建项目“scrapy_log_103”
cd scrapy_log_103\scrapy_log_103\spiders    # 进入爬虫文件所在的文件夹
scrapy genspider log www.baidu.com       # 创建爬虫文件“log.py”

在这里插入图片描述
  如下图,尝试打印一条信息,结果没有打印。

scrapy crawl log    # 执行程序

在这里插入图片描述
  如下图,注释robots协议即可正常打印。

scrapy crawl log    # 执行程序

在这里插入图片描述
在这里插入图片描述
  加一行代码后,可以看到日志信息被屏蔽。

# 指定日志的级别
LOG_LEVEL = 'WARNING'

在这里插入图片描述
  但是如果按照上图来设置后,当报错时,会看不到调试信息。为了规避这个问题,写成如下图所示的代码即可,如果代码报错,去查看日志文件即可。

# # 指定日志的级别
# LOG_LEVEL = 'WARNING'
LOG_FILE = 'logdemo.log'

在这里插入图片描述

  15.scrapy_百度翻译post请求

  (1)scrapy 下的post请求的用法

在这里插入图片描述

  (2)代码演示

  如下图,去百度翻译中打开检查,选择网络,随便输一个英文单词,然后找到它的接口并复制请求地址。
在这里插入图片描述
在这里插入图片描述
  如下图所示,创建项目和爬虫文件。
cd 爬虫的scrapy # 进入文件夹“爬虫的scrapy”

scrapy startproject scrapy_post_104   # 创建项目“scrapy_post_104”
cd scrapy_post_104\scrapy_post_104\spiders    # 进入文件夹“spiders”
scrapy genspider test_post https://fanyi.baidu.com/sug     # 创建爬虫文件“test_post.py”

在这里插入图片描述
  目前有一个问题,这个post请求会查询单词,而在代码文件“test_post.py”中看不出来它所携带的参数(即所查的单词)在什么位置。我们要知道,不含参数的post请请求是没有意义的,即start_urls没有用。由于start_urls决定着parse的执行,故方法parse也没有用。
  故在文件“test_post.py”如下编写代码。

import scrapy


class TestPostSpider(scrapy.Spider):
    name = "test_post"
    allowed_domains = ["fanyi.baidu.com"]

    # # post请求 如果没有参数 那么这个请求将没有任何意义
    # # 所以start_urls  也没有用了
    # # parse方法也没有用了
    # start_urls = ["https://fanyi.baidu.com/sug"]
    #
    # def parse(self, response):
    #     pass

    def start_requests(self):
        url = 'https://fanyi.baidu.com/sug'

        data = {
            'kw': 'final'  # 参数可在浏览器的检查里的接口的负载中查到
        }
        yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse_second)

    def parse_second(self, response):
        content = response.text
        print(content)

  去“setting.py”中设置日志信息,然后再运行程序。

# 保存日志文件
LOG_FILE = 'test_post.log'

在这里插入图片描述
  由上图知,存在编码问题。故继续在文件“test_post.py”编写代码,并运行。

import scrapy
import json


class TestPostSpider(scrapy.Spider):
    name = "test_post"
    allowed_domains = ["fanyi.baidu.com"]

    # # post请求 如果没有参数 那么这个请求将没有任何意义
    # # 所以start_urls  也没有用了
    # # parse方法也没有用了
    # start_urls = ["https://fanyi.baidu.com/sug"]
    #
    # def parse(self, response):
    #     pass

    def start_requests(self):
        url = 'https://fanyi.baidu.com/sug'

        data = {
            'kw': 'final'  # 参数可在浏览器的检查里的接口的负载中查到
        }
        yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse_second)

    def parse_second(self, response):
        content = response.text
        obj = json.loads(content)
        print(obj)

在这里插入图片描述
  好了,本章的笔记到此结束,谢谢大家阅读。写完本章博客,人都快废了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/900165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试最常问的数组转树,树转数组 c++ web框架paozhu实现

刚毕业同学&#xff0c;找工作常被问 二维数组转树&#xff0c;树转二维数组 需要支持无限层级实现&#xff0c;如果你了解这个语言那么实现起来还要一番思考 c web框架 paozhu使用 需要实现数据库表数据到前台菜单实现&#xff0c;就是这种功能 二维数组转树&#xff0c;树转…

学习笔记:Opencv实现拉普拉斯图像锐化算法

2023.8.19 为了在暑假内实现深度学习的进阶学习&#xff0c;Copy大神的代码&#xff0c;记录学习日常 图像锐化的百科&#xff1a; 图像锐化算法-sharpen_lemonHe_的博客-CSDN博客 在环境配置中要配置opencv&#xff1a; pip install opencv-contrib-python Code and lena.png…

【模拟集成电路】反馈系统——基础到进阶(一)

【模拟集成电路】反馈系统——基础到进阶 前言1 概述2 反馈电路特性2.1增益灵敏度降低2.2 终端阻抗变化2.3 带宽拓展2.4 非线性减小 3 放大器分类4 反馈检测和返回机制4.1 按照检测物理量分类4.2 按照检测拓扑连接分类 5 反馈结构分析6 二端口方法7 波特方法6 麦德布鲁克方法 前…

Go中的有限状态机FSM的详细介绍 _

1、FSM简介 1.1 有限状态机的定义 有限状态机&#xff08;Finite State Machine&#xff0c;FSM&#xff09;是一种数学模型&#xff0c;用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分&#xff1a;状态&#xff08;State&#xff09;、事件&#xff08;…

认识Spring框架

目录 1.了解Spring框架 2.了解Spring的体系结构 3.认识Spring家族 4.实现第一个Spring入门程序 1.了解Spring框架 1.什么是Spring框架&#xff1f; Spring是一个轻量级的控制反转&#xff08;IoC&#xff09;和面向切面的容器框架。 关键词概念解释&#xff1a; 1.轻量级…

2023国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

2028量产?兰博基尼首款纯电车型Lanzador亮相,双电机四驱跨界GT

经过多次预热之后&#xff0c;兰博基尼的首款纯电车型Lanzador终于在8月19日正式亮相。这款车以较完整的面貌出现在大众面前&#xff0c;将于2028年开始正式量产。虽然Lanzador仍是一个暂定名字&#xff0c;但它来自西班牙语&#xff0c;意为“投手”、“发射器”和“推动者”&…

C++笔记之注册的含义

C笔记之注册的含义 code review! 文章目录 C笔记之注册的含义1.注册对象到Qt的信号槽系统中2.注册函数到Qt的元对象系统中元对象系统例1例2 3.注册自定义类型到C STL容器中4.将函数指针传递给另一个类&#xff0c;注册回调函数class ICallback存在的意义例1&#xff0c;用于说…

专业课只考2门,计算机学硕最低分290的江苏院校

南京工业大学 考研难度&#xff08;☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分析&#xff09;、专业目录、23复试详情、各专业考情分析。 正文1332字&#xff0c;预计阅读&#xff1a;3分钟。 2023考情概况 南京工业大学计算机相关各专业复试和…

Intellij中直接运行ts配置:run configuration for typescript

在Intellij中可以借助插件run configuration for typescript直接运行typescript&#xff1a; run configuration for typescript插件本质还是依赖于 ts-node 来运行&#xff0c;只是其可以帮助我们自动配置好 ts-node 运行参数&#xff0c;简化使用。 第一步&#xff1a;安装…

uniapp配置添加阿里巴巴图标icon流程步骤

文章目录 下载复制文件到项目文件夹里项目配置目录结构显示图标 下载 阿里巴巴icon官网 https://www.iconfont.cn/ 复制文件到项目文件夹里 项目配置目录结构 显示图标

带你了解建堆的时间复杂度

目录 用向上调整建堆的时间复杂度 1.向上调整建堆的时间复杂度O(N*logN) 2.数学论证 3.相关代码 用向下调整建堆的时间复杂度 1.建堆的时间复杂度为O(N) 2.数学论证 3.相关代码 完结撒花✿✿ヽ(▽)ノ✿✿ 博主建议:面试的时候可能会被面试官问到建堆时间复杂度的证明过…

安卓手机的充电原理

安卓手机的充电原理是通过充电器将交流电转换为直流电&#xff0c;然后通过USB接口传输到手机电池中。手机电池的充电过程分为三个阶段&#xff1a;涓流充电、恒流充电和恒压充电。 充电动画 涓流充电是用来先对完全放电的电池单元进行预充&#xff08;恢复性充电&#xff09…

pdf 转 word

pdf 转 word 一、思路 直接调用LibreOffice 命令进行文档转换的命令行工具 使用的前系统中必须已经安装了 libreofficelibreoffice已翻译的用户界面语言包: 中文 (简体)libreoffice离线帮助文档: 中文 (简体)上传字体 重点&#xff1a;重点&#xff1a;重点&#xff1a; 亲…

蓝光眼镜有效吗?科研团队:无法证明防蓝光镜片可以减少视力伤害

8 月 19 日消息&#xff0c;本次由墨尔本大学、莫纳什大学和伦敦城市大学联合进行的科研团队&#xff0c;对来自 6个国家和地区的 17 项已发表的研究进行了深入研究。他们的研究发现&#xff0c;无法证明防蓝光镜片能够减少眼睛的视力伤害或改善佩戴者的睡眠质量等功效。 这项研…

【网络教程】如何获取阿里云盘的refresh_token

文章目录 获取阿里云盘的refresh_token 获取阿里云盘的refresh_token 这里在Edge浏览器上进行演示首先我们需要登入我们的阿里云盘然后按F12进入开发者模式&#xff0c;在菜单栏选择应用程序&#xff0c;然后在左边菜单找到 本地存储 下的 https://www.aliyundrive.com 这个域…

深入理解【二叉树】

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

开发过程中自己遇到的异常(四)

mysql 报错&#xff1a;‘Lost connection to MySQL server during query 出现这种情况大多是因为&#xff0c;两个事物抢一个表的使用权造成的。 show processlist; 观察Command 列&#xff0c;有明显的update&#xff0c;insert, delete 时间比较久的&#xff0c;直接kill掉…

unity 之Transform组件(汇总)

文章目录 理论指导结合例子 理论指导 当在Unity中处理3D场景中的游戏对象时&#xff0c;Transform 组件是至关重要的组件之一。它管理了游戏对象的位置、旋转和缩放&#xff0c;并提供了许多方法来操纵和操作这些属性。以下是关于Transform 组件的详细介绍&#xff1a; 位置&a…

微服务系列文章之 SpringBoot 最佳实践

Spring Boot 是一种广泛使用且非常流行的企业级高性能框架。 以下是一些最佳实践和一些技巧&#xff0c;我们可以使用它们来改进 Spring Boot 应用程序并使其更加高效。 Spring Boot 的四大核心 1、自动配置 针对很多Spring应用程序和常见的应用功能&#xff0c;Spring Boo…