美文网首页python 学习
【补充更新Report B2】Scrapy分页爬取四川大学公共管

【补充更新Report B2】Scrapy分页爬取四川大学公共管

作者: 狸狸深深 | 来源:发表于2017-05-12 14:05 被阅读539次

    目录##

    • 1.任务及目标
    • 2.创建scrapy项目
    • 3.目标网页源码分析
    • 4.爬虫思路
    • 5.scrapy shell 测试代码
    • 6.最终爬虫代码
    • 7.执行爬虫
    • 8.输出结果
    • 9.另一种处理分页的方法
    • 10.参考来源

    <b>文末补充更新Report B2</b>


    1.任务及目标##

    • 分页采集四川大学公共管理学院全职教师的基本资料及简介:
      第一页:采集教师的姓名、职称、所属系、e-mail及详细页的链接,这里需要分页采集才能采集到全部128项。
    renwu1.PNG

    第二页:通过第一页的链接进入第二页详情页,仅采集简介信息。

    renwu2.PNG
    • 期望结果
      采集到128位教师的姓名、职称、所属系、e-mail、详细页的链接及简介,输出结果teachers.json

    2.创建scrapy项目##

    scrapy startproject teachers #创建名为teachers的爬虫项目

    • 项目结构
      了解要爬取的元素后,需要自定义items.py文件


      xmjg.png

    3.目标网页源码分析##

    3.1源码分析###

    • 第一页代码:
      红线部分是我将爬取的数据
    p1html.png

    第一页分页代码,定位‘下一页’的链接,从而实现分页爬取。

    p1html1.png
    • 第二页详细页代码:我只需获取‘简介’内容
    p2html.png

    3.2编写teachers.items文件###

    • 通过以上分析得出要爬取的元素,重新编写items.py文件

      # -*- coding: utf-8 -*-
      
      # Define here the models for your scraped items
      #
      # See documentation in:
      # http://doc.scrapy.org/en/latest/topics/items.html
      
      import scrapy
      
      class TeachersItem(scrapy.Item):
        # define the fields for your item here like:
        name = scrapy.Field()   #姓名
        position = scrapy.Field()  #职称
        workfor = scrapy.Field()  #所属系
        email = scrapy.Field()  #email
        link = scrapy.Field()  #详细页链接
        desc = scrapy.Field()  #简介
      

    4.爬虫思路##

    • 入口
      start_urls=[
      'http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18&page_1_page=1',
      ]
    • 爬取第一页name positon workfor email数据,并且获得详细页链接link,并用class scrapy.http.Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback])方法,发起请求进入详情页,同时将第一页爬取的数据传值给详情页。
      <b>Request对象介绍</b>

    一个 Request
    对象代表一个HTTP请求,一般来讲, HTTP请求是由Spider产生并被Downloader处理进而生成一个 Response

    在本例中只用到url callback 这两个参数。
    url (string) :请求的URL callback(可回调):调用其他函数
    其他参数详细信息见:Requests and Responses

    <b>传递额外数据给回调函数--Request.meta</b>
    举例:

     def parse_page1(self, response):
    
        item = MyItem()
        item['main_url'] = response.url
        request = scrapy.Request("http://www.example.com/some_page.html",
                             callback=self.parse_page2)
        request.meta['item'] = item
        return request
    
     def parse_page2(self, response):
    
        item = response.meta['item']
        item['other_url'] = response.url
        return item
    

    <b>实现进入详情页并传递item数据</b>

      def parse(self,response):
        for teacher in response.xpath("//ul[@class='teachers_ul mt20 cf']/li"):
            item=TeachersItem()
            item['name']=teacher.xpath("div[@class='r fr']/h3/text()").extract_first()
            item['position']=teacher.xpath("div[@class='r fr']/p/text()").extract_first()
            item['email']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[2]/text()").extract_first()
            item['workfor']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[1]/text()").extract_first()
            href=teacher.xpath("div[@class='l fl']/a/@href").extract_first()
            request=scrapy.http.Request(response.urljoin(href),callback=self.parse_desc)
            request.meta['item']=item
            yield request
    
    • 分页爬取
      定位到“下一页”的链接,通过不断回调def parse(self,response)函数,爬取所有分页数据。

      next_page=response.xpath("//div[@class='pager cf tc pt10 pb10 mobile_dn']/li[last()-1]/a/@href").extract_first()
      last_page=response.xpath("//div[@class='pager cf tc pt10 pb10 mobile_dn']/li[last()]/a/@href").extract_first()
        if last_page:
            next_page="http://ggglxy.scu.edu.cn/"+next_page
            yield scrapy.http.Request(next_page,callback=self.parse)
      

    通过观察每个分页源代码,发现“下一页”的链接都是div的倒数第二个li元素,所以xpath路径中使用li[last()-1]
    判断是否为最后一页:最后一个li元素无href类。

    • 接收数据并处理详情页数据,最后返回的item包含了第一页和详情页的数据。

      def parse_desc(self,response):
        item=response.meta['item']
        item['link']=response.url
        item['desc']=response.xpath("//div[@class='desc']/text()").extract()
        yield item
      

    5.scrapy shell 测试代码##

    Scrapy终端是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码。 其本意是用来测试提取数据的代码,不过您可以将其作为正常的Python终端,在上面测试任何的Python代码。

    详细介绍:Scrapy终端(Scrapy shell)

    • 启动shell
      scrapy shell 'http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18&page_1_page=1'
      前面由[s]开头的是可用的对象:
    • spider:处理URL的spider。 对当前URL没有处理的Spider时则为一个 Spider
      对象。
    • request:最近获取到的页面的 Request
      对象。 您可以使用 replace()
      修改该request。或者 使用 fetch快捷方式来获取新的request。
    • response:包含最近获取到的页面的 Response
      对象。
    • sel:根据最近获取到的response构建的 Selector
      对象。
    • settings:当前的 Scrapy settings
    shell1.png
    • 用shell测试代码
      举例:
    d1.PNG d2.PNG
    • 测试完毕,退出shell,恢复爬取
      Windows系统:ctrl+z
      Unix/Linux系统:ctrl+d

    6.最终爬虫代码##

    import scrapy
    import hashlib
    
    from scrapy.selector import Selector
    from teachers.items import *
    
    
    class Teachers(scrapy.Spider):
      name="tspider"
      allowed_domains=["ggglxy.scu.edu.cn"]
      start_urls=[
        'http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18&page_1_page=1',
      ]
    
      def parse(self,response):
        for teacher in response.xpath("//ul[@class='teachers_ul mt20 cf']/li"):
          item=TeachersItem()
          item['name']=teacher.xpath("div[@class='r fr']/h3/text()").extract_first()
          item['position']=teacher.xpath("div[@class='r fr']/p/text()").extract_first()
          item['email']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[2]/text()").extract_first()
          item['workfor']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[1]/text()").extract_first()
          href=teacher.xpath("div[@class='l fl']/a/@href").extract_first()
          request=scrapy.http.Request(response.urljoin(href),callback=self.parse_desc)
          request.meta['item']=item
          yield request
    
    
        next_page=response.xpath("//div[@class='pager cf tc pt10 pb10 mobile_dn']/li[last()-1]/a/@href").extract_first()
        last_page=response.xpath("//div[@class='pager cf tc pt10 pb10 mobile_dn']/li[last()]/a/@href").extract_first()
        if last_page:
            next_page="http://ggglxy.scu.edu.cn/"+next_page
            yield scrapy.http.Request(next_page,callback=self.parse)
    
      def parse_desc(self,response):
        item=response.meta['item']
        item['link']=response.url
        item['desc']=response.xpath("//div[@class='desc']/text()").extract()
        yield item
    

    7.执行爬虫##

    执行爬虫,并保存为teachers.json文件,指定编码为utf-8,使保存下来的.json文件能用中文显示。
    执行代码:scrapy crawl tspider -o teachers.json -s FEED_EXPORT_ENCODING=utf-8

    8.输出结果##

    下载teachers.json文件:sz teachers.json
    最终结果(部分):全部结果

    {"name": "罗哲", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=89", "position": "教授", "workfor": "劳动与社会保障系", "email": "E-mail:sculuozhe@126.com", "desc": [" \n               男,中共党员,管理学博士,教授,博士生导师。四川大学公共管理学院副院长、四川大学MPA教育中心主任、四川大学人力资本开发研究所所长。国家人力资源与社会保障部培训专家、全国人力资源和社会保障职业教育教学指导委员会委员、成都市人民政府督学,中国人力资源管理教学与实践研究会理事、四川省教育学会教育人才工作委员会常务理事兼学术委员会副主任委员。主要从事公共管理、人力资源开发与管理、劳动与社会保障、教育经济与管理领域的教学与科学研究。              "]},
    {"name": "范逢春", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=86", "position": "教授", "workfor": "行政管理系", "email": "E-mail:f85418325@163.com", "desc": [" \n               范逢春,管理学博士,四川大学公共管理学院教授,院长助理,行政管理系主任,行政管理专业研究生导师、MPA导师。出版《农村公共服务多元主体协同治理机制研究》(人民出版社)、《县级政府社会治理质量测度标准研究》、《管理心理学》、《管理学》等著作、译作、教材10余部;在《管理世界》、《光明日报》、《中国行政管理》、《四川大学学报》等核心刊物发表论文40余篇;主持国家社会科学基金项目、四川省哲学社会科学项目、四川省软科学项目等各类课题20余项;获全国首批MPA优秀教学奖、四川省哲学社会科学优秀成果奖、四川省优秀教学              "]},
    {"name": "刘玲", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=87", "position": "副教授", "workfor": "行政部门", "email": "E-mail:1005730098@qq.com", "desc": [" \n               补充中···              "]},
    {"name": "罗亚玲", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=91", "position": "副教授", "workfor": "劳动与社会保障系", "email": "E-mail:s85412269@126.com", "desc": [" \n               补充中···              "]},
    {"name": "乔健", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=88", "position": "教授", "workfor": "秘书档案系", "email": "E-mail:jqiao@sina.com", "desc": [" \n               补充中···              "]},
    {"name": "姜晓萍", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=92", "position": "教授", "workfor": "行政管理系", "email": "E-mail:jxp9029@163.com", "desc": [" \n               中共党员,管理学博士,“长江学者”特聘教授。四川大学公共管理学院院长、教授,博士生导师。四川大学成都科学发展研究院院长,四川大学全国干部教育培训基地常务副主任,享受国务院政府特殊津贴专家、全国MPA教学指导委员会委员、中国政府绩效管理研究会副秘书长、中国行政管理学会常务理事、中国行政体制改革研究会理事。四川省学术带头人、四川省突出贡献专家、四川省杰出创新人才、四川省教学名师、成都市政协委员、四川省行政管理学会副会长。              "]},
    {"name": "董欢", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=7", "position": "讲师", "workfor": "土地资源与房地产管理系", "email": "E-mail:dhuan8844@126.com", "desc": [" \n               管理学博士。2016年6月获中国农业大学农业经济管理专业博士学位;2014年8月至2015年8月作为联合培养博士研究生在美国康涅狄格大学农业与资源经济系学习和开展合作研究。主要从事土地经济与管理研究,方向包括农村土地制度改革、农业经济与管理等。在《中国农村经济》、《经济学家》等CSSCI来源期刊发表学术论文数篇。", "              "]},
    {"name": "夏志强", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=90", "position": "教授", "workfor": "行政管理系", "email": "E-mail:xia6677@163.com", "desc": [" \n               经济学博士,四川大学公共管理学院教授、博士生导师、副院长,全国政治学类专业教学指导委员会委员,四川省政治学会常务理事,四川省人民政府职能转变专家组组长,成都市人民政府职能转变专家组组长,西藏自治区人民政府咨询委员,四川社会治理与公共安全研究智库首席专家,四川大学社会发展与社会风险控制研究中心(四川省社会科学重点研究基地)副主任;四川大学地方政府创新中心副主任。              "]},
    {"name": "林茂松", "link": "http://ggglxy.scu.edu.cn/index.php?c=article&id=142", "position": "讲师", "workfor": "行政部门", "email": "E-mail:linmaosong@scu.edu.cn", "desc": [" \n               补充中1              "]},
    

    9.另一种处理分页的方法##

    因为该网站的分页处理有点“怪”,一开始没找到规律,不知道如何定位到“下一页”的链接。于是求助了万能的度娘,找到这篇文章:利用Scrapy爬取1905电影网。用文章中所提到的中间件方法,可以避开定位“下一页”的步骤。所以一开始我的代码是这样的:

      def start_requests(self):
        basic_url="http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18&page_1_page=%s.html"
    
        start,end=0,16
        for i in range(start,end):
            u=re.compile("%s")
            url=u.sub(str(i),basic_url)
            yield scrapy.http.Request(url,self.parse)
    

    直接照参考文章写的话,这行代码:url = basic_url.replace("%s",str(i))会报错:AttributeError: 'str' object has no attribute 'repalce',至今不知道如何解决...所以我决定使用正则表达式(要import re)来完成字符串替换,如上代码。

    • 完整代码(已修改,之前未解决如何将两个页面数据保存到同一个item中的问题)
    import scrapy
    import re
    import hashlib
    
    from scrapy.selector import Selector
    from teachers.items import *
    
    
    class Teacher(scrapy.Spider):
      name="spider0"
      allowed_domains=["ggglxy.scu.edu.cn"]
    
    
      def start_requests(self):
        basic_url="http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18&page_1_page=%s.html"
    
        start,end=0,16
        for i in range(start,end):
          u=re.compile("%s")
          url=u.sub(str(i),basic_url)
          yield scrapy.http.Request(url,self.parse)
    
      def parse(self,response):
        for teacher in response.xpath("//ul[@class='teachers_ul mt20 cf']/li"):
          item=TeachersItem()
          item['name']=teacher.xpath("div[@class='r fr']/h3/text()").extract_first()
          item['position']=teacher.xpath("div[@class='r fr']/p/text()").extract_first()
          item['email']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[2]/text()").extract_first()
          item['workfor']=teacher.xpath("div[@class='r fr']/div[@class='desc']/p[1]/text()").extract_first()
          href=teacher.xpath("div[@class='l fl']/a/@href").extract_first()
          request=scrapy.http.Request(response.urljoin(href),callback=self.parse0)
          request.meta['item']=item
          yield request
    
    
      def parse0(self,response):
        item=response.meta['item']
        item['link']=response.url
        item['desc']=response.xpath("//div[@class='desc']/text()").extract()
        yield item
    
    • 遗留问题
      从结果看出,此爬虫并没有爬取到全部128人的数据,最终结果只有120条。(如何解决以后再说吧,好累TT,或者谁看出问题在哪,麻烦留言告知我,谢谢啦~)


      ques.png

    补充更新Report B2#

    总的来说,思路和具体过程与爬取教师资料是一样的,所以这里只上代码:

    • items.py
      # -- coding: utf-8 --

      # Define here the models for your scraped items
      #
      # See documentation in:
      # http://doc.scrapy.org/en/latest/topics/items.html
      
      import scrapy
      
      class XynewsItem(scrapy.Item):
        # define the fields for your item here like:
        ntitle = scrapy.Field()
        ndate = scrapy.Field()
        ntext = scrapy.Field()
        npic = scrapy.Field()
      
    • news.py
      import scrapy

      from scrapy.selector import Selector
      from xynews.items import *
      
      class Teachers(scrapy.Spider):
        name="nspider"
        allowed_domains=["ggglxy.scu.edu.cn"]
        start_urls=[
          'http://ggglxy.scu.edu.cn/index.php?c=special&sid=1',
        ]
      
        def parse(self,response):
          for href in response.xpath("//ul[@class='newsinfo_list_ul mobile_dn']/li/div/div[@class='news_c fr']/h3/a/@href").extract():
            yield scrapy.http.Request(response.urljoin(href),callback=self.parse_details)
            
          next_page=response.xpath("//div[@class='pager cf tr pt10 pb10 mt30 mobile_dn']/li[last()-1]/a/@href").extract_first()
          last_page=response.xpath("//div[@class='pager cf tr pt10 pb10 mt30 mobile_dn']/li[last()]/a/@href").extract_first()
          if last_page:
            next_page="http://ggglxy.scu.edu.cn/"+next_page
            yield scrapy.http.Request(next_page,callback=self.parse)
      
        def parse_details(self,response):
          item=XynewsItem()
          item['ntitle']=response.xpath("//div[@class='detail_zy_title']/h1/text()").extract()
          item['ndate']=response.xpath("//div[@class='detail_zy_title']/p/text()").extract()
          item['ntext']=response.xpath("//div[@class='detail_zy_c pb30 mb30']/p/span/text()").extract()
          item['npic']=response.xpath("//div[@class='detail_zy_c pb30 mb30']//img/@src").extract()
          yield item
      
    • news.json中部分结果
      {"ntitle": ["2016级公共管理类二班名誉班主任见面会成功举办"], "npic": ["/uploads/2017/04/011529106672.jpg", "/uploads/2017/04/011529256890.jpg", "/uploads/2017/04/011529489575.jpg", "/uploads/2017/04/011530157361.jpg"], "ntext": ["2017年3月31日下午15:50,公共管理学院2016级公共管理类二班名誉班主任见面会于知识广场大草坪成功举办。2016级公共管理类二班名誉班主任、公共管理学院副院长夏志强教授以及大类二班的全体同学共同参加了此次见面会。", "\r\n", "\r\n", "此次见面会主题是“刚好遇见你”,围绕这个主题开展了两方面活动。首先,夏志强教授带领同学们通过游戏的方式增加了了解,互动过程中气氛轻松活跃。这种人人参与的方式更是拉近了相互之间心与心的距离,为提问环节埋下良好伏笔。", "(", ")", "然后,夏志强教授分享了自己对大学学习与生活的见解与感悟。随后,他就同学们提出的诸如二专、转专业、未来规划等问题进行了详细地解答,并反复提及“快乐读书、享受学习”这一主张。除此之外,夏志强教授还与同学们在生活情感等方面进行了交流和分享,谈到十分羡慕我们还拥有着“青春”这个美好的名词。世间一切,都是遇见,就像冷遇见暖,就有了雨;春遇见冬,有了岁月;人遇见人,有了生命,与同学的遇见,有了友谊;与夏老师的遇见,就有了我们对专业与就业、未来更好的理解。", "此生有幸与你相遇,致全体二班同学及老师。", "\r\n", "\r\n"], "ndate": ["发布时间:2017-04-01"]},
      {"ntitle": ["2016级信息管理与信息系统班名誉班主任见面会成功举办"], "npic": ["/uploads/2017/04/051215556647.jpg"], "ntext": [" 2017年3月31日,公共管理学院2016级信息管理与信息系统班名誉班主任见面会成功举行。2016级信息管理与信息系统班名誉班主任李岚老师与2001级信息管理与信息系统专业韩晓东学长以及班级全体同学参加了此次活动。", " 下午2点,见面会正式开始。先是由名誉班主任李岚老师与大家进行交流与分享,李老师向同学们讲述了自己对大学生活的认识与理解,强调了兴趣是学习的动力,鼓励同学们坚持运动,保持对艺术的追求,", "将体育运动和艺术爱好贯穿整个大学生涯乃至自己的一生。李老师还强调了树立目标,学会自我管理的重要性,希望同学们度过丰富多彩、积极健康的大学生活。韩晓东学长也以他自身的经历讲述了大学四年生活、学习中的趣事,提出情商与社会实践的重要性。学长还介绍了01届信息管理与信息系统专业同学的近况,让同学们对本专业的就业趋势有了比较明晰的认识。最后学长还分享了他们精心制作的毕业十年纪念册,让大家耳目一新,受益匪浅。", " 通过此次活动,同学们明晰了大学生活的目标,明白了知识和阅历的积累对于自身发展的重要性,此次交流会取得圆满成功。", "\r\n"], "ndate": ["发布时间:2017-04-05"]},

    参考来源##

    相关文章

      网友评论

      本文标题:【补充更新Report B2】Scrapy分页爬取四川大学公共管

      本文链接:https://www.haomeiwen.com/subject/ytuotxtx.html