爬虫-Scrapy框架(vscode)

目录

Scrapy框架简介

安装

使用步骤:

搭建

创建虚拟环境

激活虚拟环境:

实例--爬取豆瓣top250

 目前数据只是第一页,接下来要进行翻页操作

更好的方法:

要写入exce;文件方法:

利用管道将数据写入excel:

利用管道将数据写入mysql:

 修改douban.py:

 一条一条数据处理写进mysql麻烦,进行批处理操作:

爬取多次网站ip被封需登录则:

 要爬取更多信息(需点开新链接):

Scrapy框架简介

引擎 (engine):Scrapy的核心,所有模块的衔接,数据流程梳理。

调度器 (scheduler):本质上这东西可以看成是一个队列,里面存放着一堆我们即将要发送的请求,可以看成是一个URL的容器。它决定了下一步要去爬取哪一个URL,通常我们在这里可以对URL进行去重操作。

下载器 (downloader):它的本质就是用来发动请求的一个模块,完全可以把它理解成实现 get_page_source() 功能的模块,只不过它返回的是一个response对象

爬虫 (spider):这是我们要写的第一个部分的内容,负责解析下载器返回的response对象,从中提取我们要的数据。

管道 (pipline):这是我们要写的第二个部分的内容,主要负责数据的存储和各种持久化操作。

经过上述的介绍来看,Scrapy其实就是把平时写的爬虫进行了四分五裂的改造,对每个功能进行了单独的封装,并且各个模块之间互相不做依赖,一切都由引擎进行调配,这种思想就叫 解耦 ,让模块与模块之间的关联性更加的松散,这样如果希望替换某一模块的时候会非常的容易,对其它模块也不会产生任何影响。

制作scrapy爬虫一共需要四步:

新建项目:新建一个爬虫项目

明确目标:明确你想要爬取的目标

制作爬虫:制作爬虫开始爬取网站

存储内容:设计管道存储爬取内容

安装

在vscode终端输入:conda install -c conda-forge scrapy

注意:vscode要改到anaconda 的python解释器才能找到安装好的scrapy库

使用步骤:

搭建

创建一个文件夹,用来存放scrapy项目

终端进入文件夹

输入

scrapy startproject 项目名(scrapywzz)

然后执行。

scrapy就会自动生成项目文件,文件夹下就会有一个scrapywzz文件夹,以及一个scrapy.cfg配置文件。

打开scrapywzz文件夹,存放爬虫文件的就是spiders文件夹。

然后在终端输入

scrapy genspider 爬虫名 域名(例如:scrapy genspider douban movie.douban.com)

创建虚拟环境

在vscode中新建终端,在终端输入如下命令:

python -m venv pyVenvTest 

(pyVenvTest 根据自己的命名修改)

激活虚拟环境:

& D:\DeskTop\Desktop\爬虫wzz\scrapywzz\venv\Scripts\Activate.ps1

提示无法加载文件xxx.venv\Scripts\activate.ps1,未对文件进行数字签名,因为在此系统上禁止运行脚本

解决方法:
第一步:以管理员身份运行powershell
第二步:执行:get-ExecutionPolicy 一般来说回复都是Restricted,表示状态是禁止的。
第三步:执行:set-ExecutionPolicy RemoteSigned
第四步:选择Y,回车

进入成功后会显示

右下角 确保解析器是自己所需要的:

 在虚拟环境中

pip install scrapy

实例--爬取豆瓣top250

安装以上步骤激活虚拟环境并确保终端位置在scrapywzz

编写douban.py中的内容:

import scrapy
#记得import一下
from scrapy import Selector
from scrapy.http import HtmlResponse
#同级引用.父级引用..
from scrapywzz.items import MovieItem


class DoubanSpider(scrapy.Spider):
    name = "douban" #爬虫名
    allowed_domains = ["movie.douban.com"] #域名
    #修改start_urls为具体实际要打开网站
    start_urls = ["https://movie.douban.com/top250"]

    def parse(self, response:HtmlResponse):
        sel=Selector(response)
        #selector支持CSS,Xpath,re
        #得到电影名li列表
        list_items=sel.css('#content > div > div.article > ol > li')
        for list_item in list_items:
            #创建MovieItem对象
            movie_item=MovieItem()
            #取电影名<span class="title">肖申克的救赎</span>中的文字
            #list_item.css('span.title::text')返回的仍然是选择器对象,所以要.extract_first()抽取里面第一条数据拿到文本内容
            movie_item['title']=list_item.css('span.title::text').extract_first()
            #取电影评分<span class="rating_num" property="v:average">9.7</span>
            movie_item['rank']=list_item.css('span.rating_num::text').extract_first()
            #取电影中心思想<span class="inq">希望让人自由。</span>
            movie_item['subject']=list_item.css('span.inq::text').extract_first()
           
           #yield用生成器方式将数据交给引擎,再由引擎交给数据管道进行后续处理
            yield movie_item

 编写items.py:

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

import scrapy

#爬虫获取的数据需要组装成Item对象(父类)
#定义一个子类MovieItem明确数据由哪些字段构成
class MovieItem(scrapy.Item):
    title=scrapy.Field()#电影名
    rank=scrapy.Field()#电影评分
    subject=scrapy.Field()#电影中心思想

 修改配置文件setting.py中USER_AGENT:

运行爬虫

scrapy crawl 爬虫名字(douban)

将数据保存至douban.csv中: 

支持csv,json,xml文件,要想放入excel需另外写代码

 结果:

 目前数据只是第一页,接下来要进行翻页操作

import scrapy
#记得import一下
from scrapy import Selector,Request
from scrapy.http import HtmlResponse
#同级引用.父级引用..
from scrapywzz.items import MovieItem


class DoubanSpider(scrapy.Spider):
    name = "douban" #爬虫名
    allowed_domains = ["movie.douban.com"] #域名
    #修改start_urls为具体实际要打开网站
    start_urls = ["https://movie.douban.com/top250"]

    #构造HtmlResponse对象 
    def parse(self, response:HtmlResponse):
        sel=Selector(response)
        #selector支持CSS,Xpath,re
        #得到电影名li列表
        list_items=sel.css('#content > div > div.article > ol > li')
        for list_item in list_items:
            #创建MovieItem对象
            movie_item=MovieItem()
            #取电影名<span class="title">肖申克的救赎</span>中的文字
            #list_item.css('span.title::text')返回的仍然是选择器对象,所以要.extract_first()抽取里面第一条数据拿到文本内容
            movie_item['title']=list_item.css('span.title::text').extract_first()
            #取电影评分<span class="rating_num" property="v:average">9.7</span>
            movie_item['rank']=list_item.css('span.rating_num::text').extract_first()
            #取电影中心思想<span class="inq">希望让人自由。</span>
            movie_item['subject']=list_item.css('span.inq::text').extract_first()
           
           #yield用生成器方式将数据交给引擎,再由引擎交给数据管道进行后续处理
            yield movie_item

        #多页解析    
        #content > div > div.article > div.paginator > a:nth-child(4)
        hrefs_list=sel.css('div.paginator > a::attr(href)')#拿取a标签的href属性
        for href in hrefs_list:
            url=response.urljoin(href.extract())
            yield Request(url=url)

 这个方法运行结果会重复爬取了第一页数据,所以不推荐

更好的方法:

import scrapy

#记得import一下
from scrapy import Selector,Request
from scrapy.http import HtmlResponse

#同级引用.父级引用..
from scrapywzz.items import MovieItem


class DoubanSpider(scrapy.Spider):
    name = "douban" #爬虫名
    allowed_domains = ["movie.douban.com"] #域名
    
    def start_requests(self):
        for page in range(10):
            yield Request(url=f'https://movie.douban.com/top250?start={page*25}&filter=')

    #构造HtmlResponse对象 **kwargs为关键词参数
    def parse(self, response:HtmlResponse,**kwargs):
        sel=Selector(response)
        #selector支持CSS,Xpath,re
        #得到电影名li列表
        list_items=sel.css('#content > div > div.article > ol > li')
        for list_item in list_items:
            #创建MovieItem对象
            movie_item=MovieItem()
            #取电影名<span class="title">肖申克的救赎</span>中的文字
            #list_item.css('span.title::text')返回的仍然是选择器对象,所以要.extract_first()抽取里面第一条数据拿到文本内容
            movie_item['title']=list_item.css('span.title::text').extract_first()
            #取电影评分<span class="rating_num" property="v:average">9.7</span>
            movie_item['rank']=list_item.css('span.rating_num::text').extract_first()
            #取电影中心思想<span class="inq">希望让人自由。</span>
            movie_item['subject']=list_item.css('span.inq::text').extract_first()
           
           #yield用生成器方式将数据交给引擎,再由引擎交给数据管道进行后续处理
            yield movie_item

此方法爬出数据正好250条

要写入exce;文件方法:

在虚拟环境内下载openpyxl:

pip install openpyxl

 额外:

若想查看已经已安装依赖项清单可以pip list或者pip freeze查看(输出在终端)

pip freeze > requirements.txt 将清单写入txt文件

pip install -r requirements.txt 将txt内所有依赖项下好

利用管道将数据写入excel:

在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
import openpyxl

#钩子方法/回调(callback)函数(方法):不需要特意调用,scrapy框架会自动调用

class ScrapywzzPipeline:

    # __init__(self)为初始化方法
    #建造工作薄
    def __init__(self):
        #Workbook为工作簿
        #ws为工作表,一个工作簿可以有多个工作表
        self.wb=openpyxl.Workbook()
        self.ws=self.wb.active #拿到默认已经激活的工作表
        #wb.create_sheet()创建一个新的工作表
        self.ws.title='top250' #命名
        self.ws.append(('标题','评分','主题'))#加入表头

    #当爬虫关闭时保存关闭文档,仅运行一次
    #注意:没用到的参数也要写进去
    def close_spider(self,spider):
        self.wb.save('电影数据.xlsx')

    #处理数据,每次拿到一条数据都要运行
    def process_item(self, item,spider):
        # self.ws.append((item['title'],item['rank'],item['subject']))
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank','')
        subject=item.get('subject','')
        self.ws.append((title,rank,subject))
        return item

修改配置文件settings.py:

运行:

scrapy crawl douban --nolog#(--nolog不显示日志)

利用管道将数据写入mysql:

先创建好数据库:

 终端下载库:

pip install pymsql

 修改douban.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
import openpyxl
import pymysql

#钩子方法/回调(callback)函数(方法):不需要特意调用,scrapy框架会自动调用

#
class Dbpipeline:
    def __init__(self):
        #连接主机
        self.conn=pymysql.connect(host='localhost',port=3306,
                                  user='root',password='root',
                                  database='wzz',charset='utf8mb4')
        self.cursor=self.conn.cursor()#创建游标对象

    def close_spider(self,spider):
        self.conn.commit()#调用 commit () 方法来确保更改生效并持久化到数据库中  
        self.conn.close()#关闭连接

    def process_item(self,item,spider):
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank',0)
        subject=item.get('subject','')
        #借助游标插入数据
        self.cursor.execute(
            '''insert into `db_top_movie`(`title`,`rank`,`subject`) values (%s,%s,%s)''',
            (title,rank,subject)#同item变量名
        )
        #记得return item,如果不return下面的管道拿不到数据
        return item

class ScrapywzzPipeline:

    # __init__(self)为初始化方法
    #建造工作薄
    def __init__(self):
        #Workbook为工作簿
        #ws为工作表,一个工作簿可以有多个工作表
        self.wb=openpyxl.Workbook()
        self.ws=self.wb.active #拿到默认已经激活的工作表
        #wb.create_sheet()创建一个新的工作表
        self.ws.title='top250' #命名
        self.ws.append(('标题','评分','主题'))#加入表头

    #当爬虫关闭时保存关闭文档,仅运行一次
    def close_spider(self,spider):
        self.wb.save('电影数据.xlsx')

    #处理数据,每次拿到一条数据都要运行
    def process_item(self, item,spider):
        # self.ws.append((item['title'],item['rank'],item['subject']))
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank','')
        subject=item.get('subject','')
        self.ws.append((title,rank,subject))
        return item

 修改settings.py

 一条一条数据处理写进mysql麻烦,进行批处理操作:

 修改douban.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
import openpyxl
import pymysql

#钩子方法/回调(callback)函数(方法):不需要特意调用,scrapy框架会自动调用

#
class Dbpipeline:
    def __init__(self):
        #连接主机
        self.conn=pymysql.connect(host='localhost',port=3306,
                                  user='root',password='root',
                                  database='wzz',charset='utf8mb4')
        self.cursor=self.conn.cursor()#创建游标对象
        self.data=[]#data容器

    def close_spider(self,spider):
        if len(self.data)>0:
            self._write_to_db()#最后观察数据没有一条但大于0仍然写进去   
        self.conn.close()#关闭连接

    def process_item(self,item,spider):       
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank',0)
        subject=item.get('subject','')
        self.data.append((title,rank,subject))#将数据放入容器
        #每100条数据写一次
        if len(self.data)==100:
            self._write_to_db()
            self.data.clear()#将data中原有100条数据清空
        #记得return item,如果不return下面的管道拿不到数据
        return item
    
    def _write_to_db(self):
        #借助游标插入数据,批处理executemany
        self.cursor.executemany(
            '''insert into `db_top_movie`(`title`,`rank`,`subject`) values (%s,%s,%s)''',
            self.data
        )
        self.conn.commit()


class ScrapywzzPipeline:

    # __init__(self)为初始化方法
    #建造工作薄
    def __init__(self):
        #Workbook为工作簿
        #ws为工作表,一个工作簿可以有多个工作表
        self.wb=openpyxl.Workbook()
        self.ws=self.wb.active #拿到默认已经激活的工作表
        #wb.create_sheet()创建一个新的工作表
        self.ws.title='top250' #命名
        self.ws.append(('标题','评分','主题'))#加入表头

    #当爬虫关闭时保存关闭文档,仅运行一次
    def close_spider(self,spider):
        self.wb.save('电影数据.xlsx')

    #处理数据,每次拿到一条数据都要运行
    def process_item(self, item,spider):
        # self.ws.append((item['title'],item['rank'],item['subject']))
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank','')
        subject=item.get('subject','')
        self.ws.append((title,rank,subject))
        return item

爬取多次网站ip被封需登录则:

1.添加代理

2.登录网站后获取cookie并设置中间件伪装用户

修改middlewares.py:

#登录账号后取cookie值
def get_cookies_dict():
    cookies_str='(复制自己的cookie)',
    cookies_dict={}
    for item in cookies_str.split('; '):
        key,value=item.split('=',maxsplit=1)
        cookies_dict[key]=value
    return cookies_dict

COOKIES_DICT=get_cookies_dict()

 配置中间件:

修改settings.py

 要爬取更多信息(需点开新链接):

修改douban.py:

import scrapy

#记得import一下
from scrapy import Selector,Request
from scrapy.http import HtmlResponse

#同级引用.父级引用..
from scrapywzz.items import MovieItem


class DoubanSpider(scrapy.Spider):
    name = "douban" #爬虫名
    allowed_domains = ["movie.douban.com"] #域名
    
    def start_requests(self):
        for page in range(10):
            yield Request(url=f'https://movie.douban.com/top250?start={page*25}&filter=')

    #构造HtmlResponse对象 **kwargs为关键词参数
    def parse(self, response:HtmlResponse,**kwargs):
        sel=Selector(response)
        #selector支持CSS,Xpath,re
        #得到电影名li列表
        list_items=sel.css('#content > div > div.article > ol > li')
        for list_item in list_items:
            #详情网站
            detail_url=list_item.css('div.info > div.hd > a::attr(href)').extract_first()
            #创建MovieItem对象
            movie_item=MovieItem()
            #取电影名<span class="title">肖申克的救赎</span>中的文字
            #list_item.css('span.title::text')返回的仍然是选择器对象,所以要.extract_first()抽取里面第一条数据拿到文本内容
            movie_item['title']=list_item.css('span.title::text').extract_first()
            #取电影评分<span class="rating_num" property="v:average">9.7</span>
            movie_item['rank']=list_item.css('span.rating_num::text').extract_first()
            #取电影中心思想<span class="inq">希望让人自由。</span>
            movie_item['subject']=list_item.css('span.inq::text').extract_first()
           
           #数据还没拿完不再是返回movie_item
            #callback不返回默认函数parse,而是返回设置的函数
            #cb_kwargs将拿到的数据继续放入movie_item
            yield Request(
                url=detail_url,callback=self.parse_detail,
                cb_kwargs={'item':movie_item}) 
    
    #解析详情页
    def parse_detail(self,response,**kwargs):
        movie_item=kwargs['item']
        sel=Selector(response)
        #片长<span property="v:runtime" content="142">142分钟</span>
        movie_item['duration']=sel.css('span[property="v:runtime"]::attr(content)').extract()
        #电影简介
        movie_item['intro']=sel.css('span[property="v:summary"]::text').extract_first() or ''
        yield movie_item

修改items.py:

 修改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
import openpyxl
import pymysql

#钩子方法/回调(callback)函数(方法):不需要特意调用,scrapy框架会自动调用

#
class Dbpipeline:
    def __init__(self):
        #连接主机
        self.conn=pymysql.connect(host='localhost',port=3306,
                                  user='root',password='root',
                                  database='wzz',charset='utf8mb4')
        self.cursor=self.conn.cursor()#创建游标对象
        self.data=[]#data容器

    def close_spider(self,spider):
        if len(self.data)>0:
            self._write_to_db()#最后观察数据没有一条但大于0仍然写进去   
        self.conn.close()#关闭连接

    def process_item(self,item,spider):       
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank',0)
        subject=item.get('subject','')
        duration=item.get('duration','')
        intro=item.get('intro','')
        self.data.append((title,rank,subject,duration,intro))#将数据放入容器
        #每100条数据写一次
        if len(self.data)==100:
            self._write_to_db()
            self.data.clear()#将data中原有100条数据清空
        #记得return item,如果不return下面的管道拿不到数据
        return item
    
    def _write_to_db(self):
        #借助游标插入数据,批处理executemany
        self.cursor.executemany(
            '''insert into `db_top_movie`(`title`,`rank`,`subject`,`duration`,`intro`) values (%s,%s,%s,%s,%s)''',
            self.data
        )
        self.conn.commit()


class ScrapywzzPipeline:

    # __init__(self)为初始化方法
    #建造工作薄
    def __init__(self):
        #Workbook为工作簿
        #ws为工作表,一个工作簿可以有多个工作表
        self.wb=openpyxl.Workbook()
        self.ws=self.wb.active #拿到默认已经激活的工作表
        #wb.create_sheet()创建一个新的工作表
        self.ws.title='top250' #命名
        self.ws.append(('标题','评分','主题','片长','简介'))#加入表头

    #当爬虫关闭时保存关闭文档,仅运行一次
    def close_spider(self,spider):
        self.wb.save('电影数据.xlsx')

    #处理数据,每次拿到一条数据都要运行
    def process_item(self, item,spider):
        # self.ws.append((item['title'],item['rank'],item['subject']))
        title=item.get('title','')#或title=item.get('title')or ''从item中拿去title,拿不到就取空值
        rank=item.get('rank','')
        subject=item.get('subject','')
        duration=item.get('duration','')
        intro=item.get('intro','')
        self.ws.append((title,rank,subject,duration,intro))
        return item

结果:

其他详细:

Scrapy 入门教程 | 菜鸟教程 (runoob.com)

scrapy爬取豆瓣电影教程-腾讯云开发者社区-腾讯云 (tencent.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值