使用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的选择器如何使用
如何使用浏览器查看指定网页元素的标签元素
四. 爬取逻辑
- 通过初始链接,先循环抓取第一页每一位老师的姓名、职称、专业、邮箱、图片链接、详情页信息。
- 详情页信息是在循环中,抓取到一位老师的详情页链接后,将链接插入爬取队列,爬取完详情页老师的剩余信息后,保存这位老师的所有信息,然后再抓取下一位老师的信息。
-
然后抓取下一页按钮的链接,若有,重复以上循环;没有,则结束。
爬取流程
五. 项目目录
scrapy_learn/
scrapy.cfg
scrapy_learn/
__init__.py
filterTags.py #网上找到的去除HTML标签的方法
items.py #定义爬取内容
pipelines.py #图片下载器
settings.py #项目设置文件
spiders/
__init__.py
tutorSpider.py #爬虫文件(编写爬虫规则)
六. 关键代码
- 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()
- 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
- 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
- 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
八. 遇到的问题
- 爬取图片的时候,没有办法爬取其他设置的item
解决:
爬取图片,写items.py文件的时候,一定要写这三行
image_urls = scrapy.Field() #图片链接
image = scrapy.Field() #图片
image_paths = scrapy.Field() #图片路径
- 爬取图片时,只能爬取带图片的老师的信息
解决:
将TutorImagePipeline类中 item_completed函数中这两行注释掉:
# if not image_paths:
# raise DropItem("Item contains no images")
这两行的意思是,这一整个item如果没有图片的话,则丢掉整个item。所以才会导致没有图片的老师信息爬取不到。
- 环境问题
安装和运行scrapy的过程中会遇到很多环境上的问题,这是因为相应的依赖没有安装好。这个时候就需要查看错误信息,然后利用百度、谷歌去搜索相应的依赖应该如何安装。
九. 运行爬虫及爬取结果
当代码编写无误后,在命令行界面中,进入项目文件夹,即scrapy_learn目录下,运行以下代码即可开始爬虫。
scrapy crawl tutor -o tutor.json
以上代码是运行爬虫,并将爬取的内容保存为json格式的文件。
爬取结果:
tutor.json
爬取照片:
爬取教师照片