爬虫-第六篇-scrapy图片爬取,请求传参,中间件,提升爬取效率

news/2024/7/7 11:41:08

补充:

自动请求start_urls列表路径其实是执行了父类中的start_requests方法,默认为GET请求,如果想要发送POST请求,改写此方法即可.

def start_requests(self):
    for url in self.start_urls:
        yield scrapy.Request(url,callback=self.parse)
# LOG_FILE = './log.txt'
日志文件输出,默认为控制台

基于scrapy进行图片数据的爬取

官方建议:使用ImagesPipeline类,也可以进行视频,音频等多媒体

  • 在爬虫文件中只需要解析提取出图片地址,然后将地址提交给管道,该管道类具有请求发送功能
  • 配置文件中:IMAGES_STORE = './imgsLib'
  • 在管道文件中进行管道类的制定:
    • 1.from scrapy.pipelines.images import ImagesPipeline
    • 2.将管道类的父类修改成ImagesPipeline
    • 3.重写父类的三个方法:
# img.py
class ImgSpider(scrapy.Spider):
    name = 'img'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.521609.com/daxuemeinv/']
    url = 'http://www.521609.com/daxuemeinv/list8%d.html'
    pageNum = 1
    def parse(self, response):
        li_list = response.xpath('//*[@id="content"]/div[2]/div[2]/ul/li')
        for li in li_list:
            img_src = 'http://www.521609.com'+li.xpath('./a[1]/img/@src').extract_first()
            item = ImgproItem()
            item['src'] = img_src

            yield item

        if self.pageNum < 3:
            self.pageNum += 1
            new_url = format(self.url%self.pageNum)
            yield scrapy.Request(new_url,callback=self.parse)
# pipelines.py
from scrapy.pipelines.images import  ImagesPipeline
import scrapy
class ImgproPipeline(ImagesPipeline):

    #对某一个媒体资源进行请求发送
    #item就是接收到的spider提交过来的item
    def get_media_requests(self, item, info):
        yield scrapy.Request(item['src'])

    #制定媒体数据存储的名称
    def file_path(self, request, response=None, info=None):
        name = request.url.split('/')[-1]
        print('正在下载:',name)
        return name

    #将item传递给下一个即将给执行的管道类
    def item_completed(self, results, item, info):
        return item

如何提升scrapy爬取数据的效率

只需要将如下五个步骤配置在配置文件中即可

  • 增加并发:
    默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。

  • 降低日志级别:
    在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’

  • 禁止cookie:
    如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False

  • 禁止重试:
    对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False

  • 减少下载超时:
    如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s

请求传参

  • 实现深度爬取:爬取多个层级对应的页面数据
  • 使用场景:爬取的数据没有在同一张页面中
  • 在手动请求的时候传递item:yield scrapy.Request(url,callback,meta={'item':item})
    • 将meta这个字典传递给callback
    • 在callback中接收meta:item = response.meta['item']
import scrapy

from moviePro.items import MovieproItem
class MovieSpider(scrapy.Spider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567tv.tv/index.php/vod/show/class/动作/id/1.html']

    url = 'https://www.4567tv.tv/index.php/vod/show/class/动作/id/1/page/%d.html'
    pageNum = 1
    def parse(self, response):
        li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
        for li in li_list:
            title = li.xpath('./div[1]/a/@title').extract_first()
            detail_url = 'https://www.4567tv.tv'+li.xpath('./div[1]/a/@href').extract_first()
            item = MovieproItem()
            item['title'] = title
            #meta参数是一个字典,该字典就可以传递给callback指定的回调函数
            yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})

        if self.pageNum < 5:
            self.pageNum += 1
            new_url = format(self.url%self.pageNum)
            yield scrapy.Request(new_url,callback=self.parse)

    def parse_detail(self,response):
        #接收meta:response.meta
        item = response.meta['item']
        desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
        item['desc'] = desc
        yield item

scrapy中的中间件的应用

  • 中间件有两种:Spider中间件,Downloader中间件,我们一般只使用下载中间件
  • 下载中间件:批量拦截请求和响应

拦截请求实现功能

  • UA伪装:将所有的请求尽可能多的设定成不同的请求载体身份标识
    • request.headers['User-Agent'] = 'xxx'
  • 代理操作:request.meta['proxy'] = 'http://ip:port'
import  random
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",

]

PROXY_http = [
    '153.180.102.104:80',
    '195.208.131.189:56055',
]
PROXY_https = [
    '120.83.49.90:9000',
    '95.189.112.214:35508',
]
class MovieproDownloaderMiddleware(object):
    #拦截正常的请求,参数request就是拦截到的请求对象
    def process_request(self, request, spider):
        #实现:将拦截到的请求尽可能多的设定成不同的请求载体身份标识
        request.headers['User-Agent'] = random.choice(user_agent_list)
        #代理操作
        if request.url.split(':')[0] == 'http':
            request.meta['proxy'] = 'http://'+random.choice(PROXY_http) #http://ip:port
        else:
            request.meta['proxy'] = 'https://' + random.choice(PROXY_https)  # http://ip:port
        return None
    #拦截响应:参数response就是拦截到的响应
    def process_response(self, request, response, spider):
        return response
    #拦截发生异常的请求
    def process_exception(self, request, exception, spider):
        #拦截到异常的请求然后对其进行修正,然后重新进行请求发送
        # 代理操作
        if request.url.split(':')[0] == 'http':
            request.meta['proxy'] = 'http://' + random.choice(PROXY_http)  # http://ip:port
        else:
            request.meta['proxy'] = 'https://' + random.choice(PROXY_https)  # http://ip:port

        return request  #将修正之后的请求进行重新发送

拦截响应:篡改响应数据或者直接替换响应对象

-需求: 爬取网易新闻的国内,国际,军事,航空,无人机这五个板块下对应的新闻标题和内容
- 分析:
- 1.每一个板块对应页面中的新闻数据是动态加载出来的

  • selenium在scrapy中的应用:
    • 实例化浏览器对象:写在爬虫类的构造方法中
    • 关闭浏览器:爬虫类中的closed(self,spider)关闭浏览器
    • 在中间件中执行浏览器自动化的操作
from time import sleep
from scrapy import signals
from scrapy.http import HtmlResponse


class WangyiproDownloaderMiddleware(object):

    def process_request(self, request, spider):
        return None

    def process_response(self, request, response, spider):#spider就是爬虫文件中爬虫类实例化的对象
        #进行所有响应对象的拦截
        #1.将所有的响应中那五个不满足需求的响应对象找出
            #1.每一个响应对象对应唯一一个请求对象
            #2.如果我们可以定位到五个响应对应的请求对象后,就可以通过该请求对象定位到指定的响应对象
            #3.可以通过五个板块的url定位请求对象
            #总结: url==》request==》response

        #2.将找出的五个不满足需求的响应对象进行修正(替换)
        #spider.five_model_urls:五个板块对应的url
        bro = spider.bro
        if request.url in spider.five_model_urls:
            bro.get(request.url)
            sleep(1)
            page_text = bro.page_source #包含了动态加载的新闻数据
            #如果if条件程利则该response就是五个板块对应的响应对象
            new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
            return new_response
        return response
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']
    five_model_urls = []
    bro = webdriver.Chrome(executable_path=r'D:\tools\chromedriver.exe')
    #用来解析五个板块对应的url,然后对其进行手动请求发送
    def parse(self, response):
        model_index = [3,4,6,7,8]
        li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
        for index in model_index:
            li = li_list[index]
            #获取了五个板块对应的url
            model_url = li.xpath('./a/@href').extract_first()
            self.five_model_urls.append(model_url)
            #对每一个板块的url进行手动i请求发送
            yield scrapy.Request(model_url,callback=self.parse_model)
    #解析每一个板块页面中的新闻标题和新闻详情页的url
    #问题:response(不满足需求的response)中并没有包含每一个板块中动态加载出的新闻数据
    def parse_model(self,response):
        div_list = response.xpath('/html/body/div[1]/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
        for div in div_list:
            title = div.xpath('./div/div[1]/h3/a/text()').extract_first()
            detail_url = div.xpath('./div/div[1]/h3/a/@href').extract_first()
            item = WangyiproItem()
            item['title'] = title
            # 对详情页发起请求解析出新闻内容
            yield scrapy.Request(detail_url,callback=self.parse_new_content,meta={'item':item})
    def parse_new_content(self,response): #解析新闻内容
        item = response.meta['item']
        content = response.xpath('//*[@id="endText"]//text()').extract()
        content = ''.join(content)

        item['content'] = content

        yield item

    #最后执行
    def closed(self,spider):
        self.bro.quit()

转载于:https://www.cnblogs.com/yinhaiping/p/11449406.html


http://www.niftyadmin.cn/n/3458651.html

相关文章

小米成立AIoT战略委员会,加速落地All in AIoT战略 ...

雷锋网(公众号&#xff1a;雷锋网)3月7日消息&#xff0c;今天下午&#xff0c;小米集团组织部再次发布任命文件&#xff0c;宣布成立AIoT战略委员会。AIoT战略委员会隶属于集团技术委员会&#xff0c;负责促进AIoT相关业务和技术部门的协同&#xff0c;推动战略落地执行。 文…

二层交换

交换网络基础 交换机工作在数据链路层 &#xff0c;通过MAC 地址转发数据帧 交换机在接受到一个主机的广播后&#xff0c;会以广播的形式从其他接口发送出去&#xff0c;这个过程叫做泛洪。 交换机在从广播中学习的 mac地址与对应的链接接口&#xff0c;写入mac表中 dis mac-a…

Spring Boot 2.2 首个里程碑版本 M1 发布

Spring Boot 2.2 首个里程碑版本 M1 已于昨天发布&#xff0c;可从里程碑仓库获取。官方表示该版本关闭了 140 多个 issue 和 PR。 有以下值得关注的更新&#xff1a; 将依赖项 Spring Data Moore 升级至 M2 版本提高配置属性数量较多时的绑定速度对 bean 进行延迟初始化的可选…

初始django

Web框架本质 https://www.cnblogs.com/liwenzhou/p/8258992.html 我们可以这样理解&#xff1a;所有的Web应用本质上就是一个socket服务端&#xff0c;而用户的浏览器就是一个socket客户端。 这样我们就可以自己实现Web框架了。 import socket sk socket.socket() sk.bind((&q…

WiFi共享命令行

通过WiFi共享命令行程序可以轻松现在无线网络共享设置&#xff0c;彻底解决了手动设置网络共享的问题。 下载设置网络共享的命令行程序下载链接&#xff1a;http://down.51cto.com/data/2459318提取码&#xff1a;aaur 一、开启WiFi共享1、开启网络承载netsh wlan set hostedn…

前端权限管理之 addRoutes 动态加载路由踩坑

这几天在开发后台管理系统的路由权限&#xff0c;在开始做之前&#xff0c;我查阅了不少资料&#xff0c;发现前后端分离的权限管理基本就以下两种方式&#xff1a; 后端生成当前用户相应的路由后由前端&#xff08;用 Vue Router 提供的API&#xff09;addRoutes 动态加载路由…

《网络攻防实践》第二周作业

一、黑客信息研究 国外黑客 凯文米特尼克(Kevin Mitnick) 1、基本信息 国籍&#xff1a;美国出生地&#xff1a;洛杉矶出生日期&#xff1a;1963年8月6日职业&#xff1a;网络安全咨询师代表作&#xff1a;《反欺骗的艺术》、《反入侵的艺术》、《线上幽灵》2、个人经历 凯文米…

(前端)html与css css 19、tab栏

做一个这个效果↓ 代码↓ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml" xml:lang"en"> &l…