scrapy全站爬取

2022-08-18 15:40:11 浏览数 (1)

笔记

代码语言:javascript复制
-基于Spider的全站数据爬取
   -基于网站中某一模板下的全部页码对应的页面数据进行爬取
   -需求:爬取校花网中的照片的名称
   -实现方式:
        -将所有的url添加到start_urls  不推荐使用
        -自行手动进行请求的发送
            # 手动请求发送 callback回调函数是专门用作与数据解析
             yield scrapy.Request(url=new_url,callback=self.parse)
 -CrawlSpider的使用
        -创建一个工程
        -cd xxx
        -创建爬虫文件(CrawlSpider):
            -Scrapy genspider -t crawl xxx www.xxx.com
            -链接提取器
                -作用:根据指定的规则(allow)进行指定链接的提取
            -规则解析器
                -作用:将连接踢球去提取到的链接进行指定规则(callback)的解析
            -follow
                -follow=True; 可以将连接提取器,继续作用到链接提取器提取到的链接,所对用的页面中
                   即使有重复的url请求,我们的调度器中的过滤器,也会帮我们给过滤掉
-五大核心组件
	Spider:主要进行数据解析
	引擎: 所有的流数据都会流经引擎1、用作数据流处理的2、可以触发事务
		
	调度器:
		过滤器:将送过来的请求进行去重,去重之后放入队列等待下一步操作
		队列:
		最终给下载器中
	下载器:从互联网上去请求网页资源 异步的操作
	管道:进行持久化存储
-请求传参

    -使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取)
    -需求:爬取boss直聘的岗位名称,岗位描述

图片爬取

需求:爬取站长素材的高清图片的爬取https://sc.chinaz.com/tupian/

笔记


基于scrapy框架爬取字符串类型的数据和爬取图片类型的数据有什么区别

​ 1、字符串,只需要xpath解析且提交管道进行持久化存储

​ 2、图片:xpath解析到图片src属性值。单独对图片地址发起请求获取图片二进制类型的数据数据

ImagesPipeline:

​ 只需要将img的src属性值进行解析,提交到管道,管道就会对图片的src进行请求发送获取到图片的二进制类型的数据,且话可以帮我们进行持久化存储

需求:爬取站长素材的图片爬取https://sc.chinaz.com/tupian/

使用流程:

​ 1、数据解析(图片的地址)

​ 2、将存储图片地址的item提交到指定的管道类

​ 3、管道文件之中自指定一个基于ImagesPipeLine的一个管道类

代码语言:javascript复制
def get_media_requests(self, item, info):
    #就是可以根据图片地址,进行图片数据的请求
def file_path(self, request, response=None, info=None, *, item=None):
    #指定图片储存的路径
def item_completed(self, results, item, info):
    return item#返回给下一个即将执行的管道类

​ 4、在配置文件中:

​ 指定图片二点存储目录:IMAGES_STORE=’./imgs_lyz’

​ 指定开启的管道:自定制的管道类


img.py

代码语言:javascript复制
import scrapy
from imgsPro.items import ImgsproItem

class ImgSpider(scrapy.Spider):
    name = 'img'
    allowed_domains = ['www.xxx.com']
    start_urls = ['https://sc.chinaz.com/tupian/']

    def parse(self, response):
        div_list=response.xpath('//*[@id="container"]/div')
        for div in div_list:
            # 注意:使用伪属性(这具体体现为,图片没在当前页面显示的话,就使用伪属性,显示出来之后才会去使用src属性)
            src=div.xpath('./div/a/img/@src2').extract_first()#//*[@id="container"]/div[1]/div/a/img/@src
            print(src)
            item = ImgsproItem()
            item ['src']='https:' src#https://scpic1.chinaz.net/Fileshttps://img.yuanmabao.com/zijie/pic/pic9/202112/apic37626_s.jpg
            yield item
        pass

pipelines.py

代码语言:javascript复制
# 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 scrapy
from itemadapter import ItemAdapter


# class ImgsproPipeline:
#     def process_item(self, item, spider):
#         return item

from scrapy.pipelines.images import ImagesPipeline
class imgsPipeline(ImagesPipeline):
    #重写父类中的三个方法
    def get_media_requests(self, item, info):
        #就是可以根据图片地址,进行图片数据的请求
        yield  scrapy.Request(item['src'])
    def file_path(self, request, response=None, info=None, *, item=None):
        #指定图片储存的路径
        img_name=request.url.split('/')[-1]
        return img_name
        pass
    def item_completed(self, results, item, info):
        return item#返回给下一个即将执行的管道类
        pass
    pass

items.py

代码语言:javascript复制
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class ImgsproItem(scrapy.Item):
    # define the fields for your item here like:
    #
    src = scrapy.Field()
    pass

setting.py

代码语言:javascript复制
USER_AGENT = 'ua检测'
ROBOTSTXT_OBEY = False
LOG_LEVEL='ERROR'

#去除注释,更改成自己写的管道类名
ITEM_PIPELINES = {
    'imgsPro.pipelines.imgsPipeline': 300,
}

#指定图片存储的目录
IMAGES_STORE='./imgs_lyz'

中间件

引擎和下载中间的是下载中间件 |||||重点

引擎和spider中间的是爬虫中间件

下载中间件:

​ 作用:批量拦截到到整个工程中所有的请求和响应

​ 拦截请求:

​ 1、UA伪装 process_request 2、代理IP的设定 process_exception return request

​ 拦截响应:

​ 1、篡改响应数据,相应对象

拦截请求

爬取百度模拟拦截之后使用ua伪装和ip代理进行爬取

middlewares.py

代码语言:javascript复制
class MiddleproDownloaderMiddleware:

    user_agent_list = [
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
        "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
        "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
        "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
        "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
        "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
        "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
        "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
        "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
        "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
        "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]

    PROXY_http = [
        '153.180.102.104:80',
        '195.208.131.189:56055',
    ]
    PROXY_https = [
        '120.83.49.90:9000',
        '95.189.112.214:35508',
    ]

    def process_request(self, request, spider):
        #拦截请求的
        #ua伪装
        request.headers['User-Agent']=random.choice(self.user_agent_list)
        return None

    def process_response(self, request, response, spider):
        #拦截所有的响应
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        #拦截发生异常的请求
        #代理IP,请求被拦截之后,换一个ip进行爬取
        if request.url.split(':')[0]=='http':
            request.meta['proxy']='http://' random.choice(self.PROXY_http)
        else:

            request.meta['proxy']='https://' random.choice(self.PROXY_https)
        return request#将修正之后的请求对象进行重新的请求发送

settings.py

代码语言:javascript复制
ROBOTSTXT_OBEY = False


DOWNLOADER_MIDDLEWARES = {
    'middlePro.middlewares.MiddleproDownloaderMiddleware': 543,
}

middle.py

代码语言:javascript复制
import scrapy


class MiddleSpider(scrapy.Spider):
    #请求的拦截,爬取百度
    name = 'middle'
    #allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.baidu.com/s?wd=ip']

    def parse(self, response):
        page_txt=response.text
        with open ('ip.html','w',encoding='utf-8')as fp:
            fp.write(page_txt)
        pass

拦截响应

需求爬取网易新闻中的新闻数据(标题和内容)

1、通过网易新闻的首页解析出来五大板块对应的详情页url(没有动态加载)

2、每一个板块对应的新闻标题都是动态加载出来的(动态加载)

3、通过解析出每一个新闻详情页的url获取详情页的页面源码,解析出来新闻内容

需求:爬取网易新闻基于Scrapy爬取网易新闻中的新闻数据


wangyi.py

代码语言:javascript复制
import scrapy
from selenium import webdriver
from wangyiPro.items import WangyiproItem

class WangyiSpider(scrapy.Spider):
    name = 'wangyi'
    allowed_domains = ['www.xxx.com']
    start_urls = ['https://news.163.com/']
    model_url_list=[]#存储五大板块对应详情页的url
    #解析五大板块对应详情页的url
    def parse(self, response):
        li_list=response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
        alist=[2,3,5,6,8]
        for index in alist:
            li=li_list[index]
            model_url=li.xpath('.//a/@href').extract_first()
            print(model_url)
            self.model_url_list.append(model_url)
        #依次对每一个板块对应的页面进行请求
        for url in self.model_url_list:
            yield scrapy.Request(url,callback=self.parse_model)
            print('第一步完成')
    #每一个板块的对应的新闻标题相关内容都是动态加载出来的
    def parse_model(self,response):
        #解析灭一个板块页面中对应的新闻的标题和新闻详情页的url
        print('第二步')
        div_list=response.xpath('/html/body/div/div[3]/div[4]/div[1]/div[1]/div/ul/li/div/div')
        for div in div_list:
            title=div.xpath('/div/div[1]/h3/a/text()').extract_first()
            new_detail_url=div.xpath('./a/@href').extract_first()
            item=WangyiproItem()
            item['title']=title
            yield scrapy.Request(url= new_detail_url, callback=self.parse_detail,meta={'item':item})
        pass


    def parse_detail(self,response):
        print('第三步')
        content=response.xpath('//*[@id="content"]/div[2]//text()').extract()
        content='' content
        item=response.meta['item']
        item['content']=content
        yield item
        pass
    # 实例化一个浏览器对象
    def __init__(self):
        self.bro=webdriver.Chrome(executable_path='chromedriver.exe')
        pass

items.py

代码语言:javascript复制
import scrapy


class WangyiproItem(scrapy.Item):
    # define the fields for your item here like:
    title=scrapy.Field()
    content= scrapy.Field()
    pass

middlewares.py

代码语言:javascript复制
from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse
from time import sleep


class WangyiproDownloaderMiddleware:

    def process_response(self, request, response, spider):
        #通过该方法拦截五大板块对应的响应对象,进行篡改
        #挑选出指定的响应对象进行篡改
        #spider是爬虫的对象
        bro=spider.bro#获取了爬虫类中定义的浏览器对象
        if request.url in spider.model_url_list:
            # response#五大板块对应的响应对象
            #针对定位到这些的response进行篡改
            #实例化一个新的响应对象(符合需求:包含动态加载出来的新闻数据),代替原来旧的响应对象
            #如何获取动态加载的数据
            # 基于selenium便捷的获取动态加载的数据
            bro.get(request.url)  # 五大板块对应的url进行请求发送
            sleep(5)
            page_text = bro.page_source  # 包含了动态记载的新闻数据
            new_response=HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
            return new_response
        else:
            #response#其他请求对应的响应对象
            return response

    def process_exception(self, request, exception, spider):
        pass

pipelines.py

代码语言:javascript复制
class WangyiproPipeline:
    # 专门用来处理item类型对象
    # 该方法可以接受爬虫文件提交过来的item对象
    # 该方法没接收到一个item就会被调用一次
    def process_item(self, item, spider):
       print(item)
       return item

CrawlSpider

他就是一个基于spider的一个子类CrawlSpider;专门去做的全站数据的爬取

全站数据爬取的方式

基于spider:手动请求发送(利用页面通用的url进行页面的请求的发送)

基于CrawlSpider:

CrawlSpider的具体使用

1、创建一个工程

2、cd XXX

3、创建爬虫文件(CrawlSpider):

代码语言:javascript复制
# 创建爬虫文件
scrapy genspider -t crawl xxx www.xxx.com

链接提取器:根据指定规则(allow=r’Items/ r’Items/‘是一个正则表达式)进行指定连接的提取,根据指定规则allow,进行连接爬取

规则解析器:将链接解析器提取到的链接进行制定规则(callback)的解析操作

找不到url链接提取去没有用没有再看

demo

代码语言:javascript复制
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from lxml import etree

#这个就是全站爬取的demo
#5.18这个针对于个人信息,可以利用他的搜索进行查找到每一个人对应的数据,这个将大大降低我们搜索的时间和难度;针对于他的题库类型要使用全站爬取的这种方式进行爬取
class DemoproSpider(CrawlSpider):
    name = 'demoPro'
    #allowed_domains = ['www.xxx.com']
    start_urls = ['http://acm.zzuli.edu.cn/ranklist.php']
    # 实例化了一个规则解析器;
    # 三个参数所表示的意思
    # LinkExtractor链接提取器:根据指定规则(allow="正则表达式"),进行指定连接的提取
    link=LinkExtractor(allow=r'start=d ')
    rules = (
        #规则解析器 将链接提取器提取到的链接进行制定规则(callback)的解析操作
        #链接提取器提取到的链接,callback就会执行几次
        Rule(link, callback='parse_item', follow=True),
        #follow=True; 可以将连接提取器,继续作用到链接提取器提取到的链接,所对用的页面中
        #即使有重复的url请求,我们的调度器中的过滤器,也会帮我们给过滤掉
    )

    def parse_item(self, response):#大概就是做数据分析的
        item = {}
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        #item['name'] = response.xpath('//div[@id="name"]').get()
        #item['description'] = response.xpath('//div[@id="description"]').get()
        print(response)
        item = {}
        page_txt = response.text
        # /html/body/div[1]/div/table/tbody
        tree = etree.HTML(page_txt)
        tr_list = tree.xpath('/html/body/div[1]/div/table/tbody/tr')
        for item in tr_list:
            userid = item.xpath('./td[2] / div / a/text()')[0]
            username = item.xpath('./td[3]/div/text()')[0]
            adad = item.xpath('./td[4]/div/a/text()')[0]
            qweqwe = item.xpath("./td[5]/div/a/text()")[0]
            bilv = item.xpath("./td[6]/div/text()")[0]
            jibie = item.xpath("./td[7]/div/text()")[0]
            #if userid == "201908064618":
            print(userid   "||"   username   "|"   adad   "||"   qweqwe   "||"   bilv   "||"   jibie)
        print(tr_list.__len__())
        return item

问题

小插曲

时间长没有做python了,又重装了系统,这爬虫这部分就一直在搁置,这打开程序发现终端识别不到scrapy程序命令。但是在pycharm确实是下载的又这个库

解决

就是在终端删除这个库,我的是他就提示这个库它本身就没有下载,然后我就先下载了一下

0 人点赞