zoukankan      html  css  js  c++  java
  • 项目案例(爬取网易新闻)

    编辑本随笔

    bobo博客

    案例需求

    爬取网易新闻基于文字的新闻,板块包括国内、国际、军事、航空等四个板块

    获取指定板块超链接

    import scrapy
    class WangyiSpider(scrapy.Spider):
        name = 'wangyi'
        #allowed_domains = ['news.163.com']
        start_urls = ['https://news.163.com/']
    
        def parse(self, response):
            lis=response.xpath("//div[@class='ns_area list']/ul/li")
            indexs=[3,4,6,7]
            li_list=[]
            for index in indexs:
                li_list.append(lis[index])
            #获取四个板块中的链接和文字标题
            for li in li_list:
                url=li.xpath("./a/@href").extract_first()
                title=li.xpath("./a/text()").extract_first()
                print(title+":"+url)

    从页面中提取需要内容

    此处并未提取到内容,因实际内容是动态加载的,所以直接用xpath解析不出内容

    # -*- coding: utf-8 -*-
    import scrapy
    class WangyiSpider(scrapy.Spider):
        name = 'wangyi'
        #allowed_domains = ['news.163.com']
        start_urls = ['https://news.163.com/']
    
        def parse(self, response):
            lis=response.xpath("//div[@class='ns_area list']/ul/li")
            indexs=[3,4,6,7]
            li_list=[]
            for index in indexs:
                li_list.append(lis[index])
            #获取四个板块中的链接和文字标题
            for li in li_list:
                url=li.xpath("./a/@href").extract_first()
                title=li.xpath("./a/text()").extract_first()
                print(title+":"+url)
                #对每个板块对应的url发起请求,获取页面数据(标题,缩略图,关键字,发布时间,url)
                yield scrapy.Request(url=url,callback=self.parseSecond)
        def parseSecond(self,response):
            div_list=response.xpath("//div[@class='data_row news_article clearfix']")
            for div in div_list:
                head=div.xpath(".//div[@class='news_title']/h3/a/text()").extract_first()
                url = div.xpath(".//div[@class='news_title']/h3/a/@href").extract_first()
                img_url=div.xpath("./a/img/@src").extract_first()
                tag=",".join(div.xpath(".//div[@class='news_tag']/div//text()"))
                time=div.xpath(".//div[@class='news_tag']/span/text()").extract_first()
    View Code

    重写中间件,使用浏览器进行数据下载

    wangyi.py爬虫文件

    # -*- coding: utf-8 -*-
    import scrapy
    from selenium import webdriver
    class WangyiSpider(scrapy.Spider):
        name = 'wangyi'
        #allowed_domains = ['news.163.com']
        start_urls = ['https://news.163.com/']
        def __init__(self):
            #实例化一个浏览器,只需要执行一次
            self.bro=webdriver.Chrome(executable_path="/home/yaya/paChong/wangyiPro/wangyiPro/spiders/chromedriver.exe")
        def closed(self,spider):
            #实现父类方法,爬虫结束时调用
            print("爬虫结束")
            self.bro.quit()
        def parse(self, response):
            lis=response.xpath("//div[@class='ns_area list']/ul/li")
            indexs=[3,4,6,7]
            li_list=[]
            for index in indexs:
                li_list.append(lis[index])
            #获取四个板块中的链接和文字标题
            for li in li_list:
                url=li.xpath("./a/@href").extract_first()
                title=li.xpath("./a/text()").extract_first()
                #对每个板块对应的url发起请求,获取页面数据(标题,缩略图,关键字,发布时间,url)
                yield scrapy.Request(url=url,callback=self.parseSecond)
        def parseSecond(self,response):
            # div_list=response.xpath('//div[@class="data_row news_article clearfix"]')ndi_main
            div_list = response.xpath('//div[@class="ndi_main"]/div')
            print(len(div_list))
            for div in div_list:
                head=div.xpath(".//div[@class='news_title']/h3/a/text()").extract_first()
                url = div.xpath(".//div[@class='news_title']/h3/a/@href").extract_first()
                img_url=div.xpath("./a/img/@src").extract_first()
                tag=",".join(div.xpath(".//div[@class='keywords']//a/text()").extract())
                time=div.xpath(".//div[@class='news_tag']/span/text()").extract_first()
                print(head)
                print(url)
                print(img_url)
                print(tag)
                print(time)
    View Code

    重写下载中间件

    from scrapy.http import HtmlResponse
    class WangyiproDownloaderMiddleware(object):
    
        def process_request(self, request, spider):
            return None
    
        #拦截到响应对象,即下载器传递给spider的响应对象
        def process_response(self, request, response, spider):
            #request:响应对象对应的请求对象
            #response:拦截到的响应对象
            #spider:爬虫文件中对应的爬虫类实例
            if request.url in ["http://news.163.com/domestic/","http://news.163.com/world/","http://war.163.com/","http://news.163.com/air/"]:
                spider.bro.get(url=request.url)
                page_text=spider.bro.page_source
                with open("./domestic.html","w",encoding="utf8") as fp:
                    fp.write(page_text)
                #自己封装response,并返回
                return HtmlResponse(url=spider.bro.current_url,body=page_text,encoding="utf-8",request=request)
            else:
                return response

    在配置文件中开启下载中间件

    DOWNLOADER_MIDDLEWARES = {
       'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
    }

    测试中间件作用情况:

    获取新闻内容

    编写items.py,添加所需字段

    import scrapy
    class WangyiproItem(scrapy.Item):
        head = scrapy.Field()
        tag = scrapy.Field()
        url = scrapy.Field()
        img_url = scrapy.Field()
        title=scrapy.Field()
        content=scrapy.Field()
    View Code

    爬虫文件中添加对应页面解析函数

    import scrapy
    from selenium import webdriver
    from wangyiPro.items import WangyiproItem
    class WangyiSpider(scrapy.Spider):
        name = 'wangyi'
        #allowed_domains = ['news.163.com']
        start_urls = ['https://news.163.com/']
        def __init__(self):
            #实例化一个浏览器,只需要执行一次
            self.bro=webdriver.Chrome(executable_path="/home/yaya/paChong/wangyiPro/wangyiPro/spiders/chromedriver.exe")
        def closed(self,spider):
            #实现父类方法,爬虫结束时调用
            print("爬虫结束")
            self.bro.quit()
        def parse(self, response):
            lis=response.xpath("//div[@class='ns_area list']/ul/li")
            indexs=[3,4,6,7]
            li_list=[]
            for index in indexs:
                li_list.append(lis[index])
            #获取四个板块中的链接和文字标题
            for li in li_list:
                url=li.xpath("./a/@href").extract_first()
                title=li.xpath("./a/text()").extract_first()
                #对每个板块对应的url发起请求,获取页面数据(标题,缩略图,关键字,发布时间,url)
                yield scrapy.Request(url=url,callback=self.parseSecond,meta={"title":title})
        def parseSecond(self,response):
            #解析每个类页面中的新闻链接和相关信息
            div_list = response.xpath('//div[@class="ndi_main"]/div')
            for div in div_list:
                head=div.xpath(".//div[@class='news_title']/h3/a/text()").extract_first()
                url = div.xpath(".//div[@class='news_title']/h3/a/@href").extract_first()
                img_url=div.xpath("./a/img/@src").extract_first()
                tag=",".join(div.xpath(".//div[@class='keywords']//a/text()").extract())
                time=div.xpath(".//div[@class='news_tag']/span/text()").extract_first()
                #实例化item对象,将解析到的值存储到item中
                item=WangyiproItem()
                item["head"]=head
                item["url"]=url
                item["img_url"]=img_url
                item["tag"]=tag
                item["title"] = response.meta["title"]
                yield scrapy.Request(url=url,callback=self.getContent,meta={"item":item})
        def getContent(self,response):
            #解析新闻文本内容
            item=response.meta.get("item")
            content_list=response.xpath("//div[@class='post_text']/p/text()").extract()
            content="
    ".join(content_list)
            item["content"]=content
            yield item
    View Code

    在pipelines文件中做输出测试

    class WangyiproPipeline(object):
        def process_item(self, item, spider):
            print(item["title"])
            print(item["content"])
            return item
    View Code

    在setting中开启管道文件

    ITEM_PIPELINES = {
       'wangyiPro.pipelines.WangyiproPipeline': 300,
    }
    View Code

    JS动态加载更多数据

    重写下载中间件,模拟浏览器滚动到最底部

    class WangyiproDownloaderMiddleware(object):
    
        def process_request(self, request, spider):
            return None
    
        #拦截到响应对象,即下载器传递给spider的响应对象
        def process_response(self, request, response, spider):
            #request:响应对象对应的请求对象
            #response:拦截到的响应对象
            #spider:爬虫文件中对应的爬虫类实例
            if request.url in ["http://news.163.com/domestic/","http://news.163.com/world/","http://war.163.com/","http://news.163.com/air/"]:
                spider.bro.get(url=request.url)
    
                #将滚轮滚动到最底部
                js="window.scrollTo(0,document.body.scrollHeight)"
                spider.bro.execute_script(js)
                #如果没有获取到更多的数据,这里给浏览器一定的加载时间
                #time.sleep(3
                page_text=spider.bro.page_source
                with open("./domestic.html","w",encoding="utf8") as fp:
                    fp.write(page_text)
                #自己封装response,并返回
                return HtmlResponse(url=spider.bro.current_url,body=page_text,encoding="utf-8",request=request)
            else:
                return response

    selenium应用到scrapy框架流程总结

    1. 在爬虫文件中导入webdriver类
    2. 在爬虫类的构造方法中,进行浏览器实例化操作,实例化一次即可
    3. 在爬虫类的closed方法中进行浏览器关闭操作
    4. 在下载中间件process_response方法中进行浏览器的自动化操作

    基于RedisSpider分布式爬取

    1. 代码修改
      • 导包from scrapy_redis.spiders import RedisSpider
      • 将项目父类修改成RedisSpider
      • 将起始URL列表注释,并添加一个redis_key的属性(调度队列的名称)
    2. redis数据库配置文件(redis.conf)修改
      • 修改绑定地址bind 127.0.0.1,指定其他电脑可访问的地址
      • 关闭保护模式protected-mode no
      • 开启redis数据库服务 redis-server redis.conf
    3. 对项目settings.py进行配置
      • 配置redis服务器的IP和端口REDIS_HOST="127.0.0.1",REDIS_PORT=6379
        # 是否允许暂停,即程序意外宕机重启后从上次意外退出的地方重新爬取
        SCHEDULER_PERSIST = True
        
        #Redis服务器地址,代码拷贝到其他服务器后,爬取的数据将保存到如下地址的redis服务器中
        REDIS_HOST="192.168.1.1"
        
        #Redis服务器端口
        REDIS_PORT=6379
      • 修改默认调度器为可共享调度器和去重队列
        # 使用scrapy-redis组件的去重队列进行去重操作
        DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
        
        # 使用scrapy-redis组件自己的调度器
        SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      • 修改默认管道为可共享管道
        #使用组件封装的管道,不使用原生的管道
        ITEM_PIPELINES = {
           'scrapy_redis.pipelines.RedisPipeline': 300,
        }
    4. 执行爬虫文件scrapy runspider wangyi.py
    5. 向调度器队列中放入一个起始url
      • 打开redis客户端
    6. 查看爬取数据
  • 相关阅读:
    java流程控制02Scanner进阶使用
    java流程控制01用户交互scanner
    java流程控制05Switch选择结构
    java基础10三元运算符
    CSDN的轮换广告JS
    如何在DataGrid中加入javascript以进行客户端的操作
    Json 的日期格式到.net datetime格式
    利用web.config设置用户不被锁定
    用csc.exe编译程序的例子
    严重关注食物安全
  • 原文地址:https://www.cnblogs.com/yaya625202/p/10435180.html
Copyright © 2011-2022 走看看