使用scrapy爬取四川大学公共管理学院教师信息实验报告

2018-05-12  本文已影响0人  菜菜不太菜

在参考zl、lly以及各种教程的代码后,完成了爬取教师名称、职称、专业、邮箱、图片、简介、研究成果、获奖成果、科研项目和人才培养信息的实验。具体代码可从我的github上面下载运行。

一. 实验环境

windows 10
python2.7.15
IDE:Eclipse+PyDev
scrapy 1.5.0

二. 实验前需安装的库

scrapy, PIL
安装指令

pip install scrapy
pip install pillow

scrapy在windows下需要成功运行的话,还需要安装pywin32

三. 需要掌握的知识

scrapy的基础知识
xpath或者css的选择器如何使用
如何使用浏览器查看指定网页元素的标签元素

四. 爬取逻辑

  1. 通过初始链接,先循环抓取第一页每一位老师的姓名、职称、专业、邮箱、图片链接、详情页信息。
  2. 详情页信息是在循环中,抓取到一位老师的详情页链接后,将链接插入爬取队列,爬取完详情页老师的剩余信息后,保存这位老师的所有信息,然后再抓取下一位老师的信息。
  3. 然后抓取下一页按钮的链接,若有,重复以上循环;没有,则结束。


    爬取流程

五. 项目目录

scrapy_learn/
    scrapy.cfg
    scrapy_learn/
        __init__.py
        filterTags.py  #网上找到的去除HTML标签的方法
        items.py  #定义爬取内容
        pipelines.py  #图片下载器
        settings.py    #项目设置文件
        spiders/
            __init__.py
            tutorSpider.py    #爬虫文件(编写爬虫规则)

六. 关键代码

  1. items.py
    定义要爬取的内容

# -*- coding: utf-8 -*-

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

import scrapy


class TutorItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field() #姓名
    position = scrapy.Field() #职称
    major = scrapy.Field() #专业
    email = scrapy.Field() #邮箱
    description = scrapy.Field()  #简介
    researchResult = scrapy.Field() #代表性研究成果
    award = scrapy.Field() #获奖情况
    sciResearPro = scrapy.Field() #科研项目
    talentTrain = scrapy.Field() #人才培养
    image_urls = scrapy.Field() #图片链接
    image = scrapy.Field() #图片
    image_paths = scrapy.Field()
  1. TutorSpider.py
    编写爬虫规则
# -*- coding:UTF-8 -*-
import scrapy
from scrapy_learn.items import TutorItem
from scrapy_learn.filterTags import filter_tags



class TutorSpider(scrapy.Spider):
    name = 'tutor'
    allowed_domains = ['ggglxy.scu.edu.cn']
    start_urls=['http://ggglxy.scu.edu.cn/index.php?c=article&a=type&tid=18']
    # 初始化item对象保存爬取的信息
    item = TutorItem()
    
    def parse(self,response):
        for tutor in response.xpath("//li[@class='fl']"):
            # 爬取姓名,职称,专业,邮箱
            item = TutorItem()
            item['image_urls'] = {"http://ggglxy.scu.edu.cn"+tutor.xpath("div[@class='l fl']/a/img/@src").extract_first()}
            item['name'] = tutor.xpath("div[@class='r fr']/h3[@class='mb10']/text()").extract_first()
            item['position'] = tutor.xpath("div[@class='r fr']/p[@class='color_main f14']/text()").extract_first()
            item['major'] = tutor.xpath("div[@class='r fr']/div[@class='desc']/p[1]/text()").extract_first()
            item['email'] = tutor.xpath("div[@class='r fr']/div[@class='desc']/p[2]/text()").extract_first()
             
            # 获取详情页的地址并传送给单个页面处理函数进行处理 -> parse_details()
            href = tutor.xpath("div[@class='l fl']/a/@href").extract_first()
            url = response.urljoin(href)
            request = scrapy.Request(url,callback=self.parse_details)
            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()
        if next_page is not None:
            next_pages = response.urljoin(next_page)
            ## 将 「下一页」的链接传递给自身,并重新分析
            yield scrapy.Request(next_pages, callback = self.parse)

    # 编写详情页爬取方法
    def parse_details(self, response):
        item = response.meta['item']
        item['description'] = response.xpath("//div[@class='r fr']/div/text()").extract_first()
        item['researchResult'] = filter_tags(response.xpath("//div[@class='right_info p20']/div[2]").extract_first())
        item['award'] = filter_tags(response.xpath("//div[@class='right_info p20']/div[3]").extract_first())
        item['sciResearPro'] = filter_tags(response.xpath("//div[@class='right_info p20']/div[4]").extract_first())
        item['talentTrain'] = filter_tags(response.xpath("//div[@class='right_info p20']/div[5]").extract_first())
        yield item
  1. pipelines.py
    下载图片
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html



import scrapy
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem

class ScrapyLearnPipeline(object):
    def process_item(self, item, spider):
        return item
 
class TutorImagesPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        for image_url in item['image_urls']:
            yield scrapy.Request(image_url)
 
    def item_completed(self,results,item,info):
        image_paths = [x['path'] for ok,x in results if ok]
#         if not image_paths:
#             raise DropItem("Item contains no images")
        item['image_paths'] = image_paths
        return item
  1. filterTags.py
    去除HTML标签
# -*- coding: utf-8-*-  
import re  
##过滤HTML中的标签  
#将HTML中标签等信息去掉  
#@param htmlstr HTML字符串.  
def filter_tags(htmlstr):  
    #先过滤CDATA  
    re_cdata=re.compile('//<!CDATA\[[>]∗//CDATA\[[>]∗//\]>',re.I) #匹配CDATA  
    re_script=re.compile('<\s*script[^>]*>[^<]*<\s*/\s*script\s*>',re.I)#Script  
    re_style=re.compile('<\s*style[^>]*>[^<]*<\s*/\s*style\s*>',re.I)#style  
    re_br=re.compile('<br\s*?/?>')#处理换行  
    re_h=re.compile('</?\w+[^>]*>')#HTML标签  
    re_comment=re.compile('<!--[^>]*-->')#HTML注释  
    s=re_cdata.sub('',htmlstr)#去掉CDATA  
    s=re_script.sub('',s) #去掉SCRIPT  
    s=re_style.sub('',s)#去掉style  
    s=re_br.sub('\n',s)#将br转换为换行  
    s=re_h.sub('',s) #去掉HTML 标签  
    s=re_comment.sub('',s)#去掉HTML注释  
    #去掉多余的空行  
    blank_line=re.compile('\n+')  
    s=blank_line.sub('\n',s)  
    s=replaceCharEntity(s)#替换实体  
    return s  
  
##替换常用HTML字符实体.  
#使用正常的字符替换HTML中特殊的字符实体.  
#你可以添加新的实体字符到CHAR_ENTITIES中,处理更多HTML字符实体.  
#@param htmlstr HTML字符串.  
def replaceCharEntity(htmlstr):  
    CHAR_ENTITIES={'nbsp':' ','160':' ',  
                'lt':'<','60':'<',  
                'gt':'>','62':'>',  
                'amp':'&','38':'&',  
                'quot':'"''"','34':'"',}  
      
    re_charEntity=re.compile(r'&#?(?P<name>\w+);')  
    sz=re_charEntity.search(htmlstr)  
    while sz:  
        entity=sz.group()#entity全称,如>  
        key=sz.group('name')#去除&;后entity,如>为gt  
        try:  
            htmlstr=re_charEntity.sub(CHAR_ENTITIES[key],htmlstr,1)  
            sz=re_charEntity.search(htmlstr)  
        except KeyError:  
            #以空串代替  
            htmlstr=re_charEntity.sub('',htmlstr,1)  
            sz=re_charEntity.search(htmlstr)  
    return htmlstr  
  
def repalce(s,re_exp,repl_string):  
    return re_exp.sub(repl_string,s)  

七. 项目设置

要输出中文到文件中,需要在settings.py中加入

FEED_EXPORT_ENCODING = 'utf-8'

要爬取图片到本地,需要在settings.py中加入

ITEM_PIPELINES = {
    'scrapy_learn.pipelines.TutorImagesPipeline': 1,
}
IMAGES_STORE = 'D:\MyWorkspace\PythonWorkspace\scrapy_learn\img' #图片存储目录
# 30天的图片失效期限
IMAGES_EXPIRES = 30

八. 遇到的问题

  1. 爬取图片的时候,没有办法爬取其他设置的item
    解决:
    爬取图片,写items.py文件的时候,一定要写这三行
image_urls = scrapy.Field() #图片链接
image = scrapy.Field() #图片
image_paths = scrapy.Field() #图片路径
  1. 爬取图片时,只能爬取带图片的老师的信息
    解决:
    将TutorImagePipeline类中 item_completed函数中这两行注释掉:
#         if not image_paths:
#             raise DropItem("Item contains no images")

这两行的意思是,这一整个item如果没有图片的话,则丢掉整个item。所以才会导致没有图片的老师信息爬取不到。

  1. 环境问题
    安装和运行scrapy的过程中会遇到很多环境上的问题,这是因为相应的依赖没有安装好。这个时候就需要查看错误信息,然后利用百度、谷歌去搜索相应的依赖应该如何安装。

九. 运行爬虫及爬取结果

当代码编写无误后,在命令行界面中,进入项目文件夹,即scrapy_learn目录下,运行以下代码即可开始爬虫。

scrapy crawl tutor -o tutor.json

以上代码是运行爬虫,并将爬取的内容保存为json格式的文件。
爬取结果:


tutor.json

爬取照片:


爬取教师照片
上一篇下一篇

猜你喜欢

热点阅读