在參考zl、lly以及各種教程的代碼后,完成了爬取教師名稱、職稱、專業(yè)、郵箱、圖片、簡(jiǎn)介、研究成果、獲獎(jiǎng)成果、科研項(xiàng)目和人才培養(yǎng)信息的實(shí)驗(yàn)。具體代碼可從我的github上面下載運(yùn)行。
一. 實(shí)驗(yàn)環(huán)境
windows 10
python2.7.15
IDE:Eclipse+PyDev
scrapy 1.5.0
二. 實(shí)驗(yàn)前需安裝的庫(kù)
scrapy, PIL
安裝指令
pip install scrapy
pip install pillow
scrapy在windows下需要成功運(yùn)行的話,還需要安裝pywin32
三. 需要掌握的知識(shí)
scrapy的基礎(chǔ)知識(shí)
xpath或者css的選擇器如何使用
如何使用瀏覽器查看指定網(wǎng)頁(yè)元素的標(biāo)簽元素
四. 爬取邏輯
- 通過(guò)初始鏈接,先循環(huán)抓取第一頁(yè)每一位老師的姓名、職稱、專業(yè)、郵箱、圖片鏈接、詳情頁(yè)信息。
- 詳情頁(yè)信息是在循環(huán)中,抓取到一位老師的詳情頁(yè)鏈接后,將鏈接插入爬取隊(duì)列,爬取完詳情頁(yè)老師的剩余信息后,保存這位老師的所有信息,然后再抓取下一位老師的信息。
-
然后抓取下一頁(yè)按鈕的鏈接,若有,重復(fù)以上循環(huán);沒(méi)有,則結(jié)束。
爬取流程
五. 項(xiàng)目目錄
scrapy_learn/
scrapy.cfg
scrapy_learn/
__init__.py
filterTags.py #網(wǎng)上找到的去除HTML標(biāo)簽的方法
items.py #定義爬取內(nèi)容
pipelines.py #圖片下載器
settings.py #項(xiàng)目設(shè)置文件
spiders/
__init__.py
tutorSpider.py #爬蟲(chóng)文件(編寫爬蟲(chóng)規(guī)則)
六. 關(guān)鍵代碼
- items.py
定義要爬取的內(nèi)容
# -*- 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() #專業(yè)
email = scrapy.Field() #郵箱
description = scrapy.Field() #簡(jiǎn)介
researchResult = scrapy.Field() #代表性研究成果
award = scrapy.Field() #獲獎(jiǎng)情況
sciResearPro = scrapy.Field() #科研項(xiàng)目
talentTrain = scrapy.Field() #人才培養(yǎng)
image_urls = scrapy.Field() #圖片鏈接
image = scrapy.Field() #圖片
image_paths = scrapy.Field()
- TutorSpider.py
編寫爬蟲(chóng)規(guī)則
# -*- 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對(duì)象保存爬取的信息
item = TutorItem()
def parse(self,response):
for tutor in response.xpath("http://li[@class='fl']"):
# 爬取姓名,職稱,專業(yè),郵箱
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()
# 獲取詳情頁(yè)的地址并傳送給單個(gè)頁(yè)面處理函數(shù)進(jìn)行處理 -> 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
## 是否還有下一頁(yè),如果有的話,則繼續(xù)
next_page=response.xpath("http://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)
## 將 「下一頁(yè)」的鏈接傳遞給自身,并重新分析
yield scrapy.Request(next_pages, callback = self.parse)
# 編寫詳情頁(yè)爬取方法
def parse_details(self, response):
item = response.meta['item']
item['description'] = response.xpath("http://div[@class='r fr']/div/text()").extract_first()
item['researchResult'] = filter_tags(response.xpath("http://div[@class='right_info p20']/div[2]").extract_first())
item['award'] = filter_tags(response.xpath("http://div[@class='right_info p20']/div[3]").extract_first())
item['sciResearPro'] = filter_tags(response.xpath("http://div[@class='right_info p20']/div[4]").extract_first())
item['talentTrain'] = filter_tags(response.xpath("http://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標(biāo)簽
# -*- coding: utf-8-*-
import re
##過(guò)濾HTML中的標(biāo)簽
#將HTML中標(biāo)簽等信息去掉
#@param htmlstr HTML字符串.
def filter_tags(htmlstr):
#先過(guò)濾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*?/?>')#處理?yè)Q行
re_h=re.compile('</?\w+[^>]*>')#HTML標(biāo)簽
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轉(zhuǎn)換為換行
s=re_h.sub('',s) #去掉HTML 標(biāo)簽
s=re_comment.sub('',s)#去掉HTML注釋
#去掉多余的空行
blank_line=re.compile('\n+')
s=blank_line.sub('\n',s)
s=replaceCharEntity(s)#替換實(shí)體
return s
##替換常用HTML字符實(shí)體.
#使用正常的字符替換HTML中特殊的字符實(shí)體.
#你可以添加新的實(shí)體字符到CHAR_ENTITIES中,處理更多HTML字符實(shí)體.
#@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)
七. 項(xiàng)目設(shè)置
要輸出中文到文件中,需要在settings.py中加入
FEED_EXPORT_ENCODING = 'utf-8'
要爬取圖片到本地,需要在settings.py中加入
ITEM_PIPELINES = {
'scrapy_learn.pipelines.TutorImagesPipeline': 1,
}
IMAGES_STORE = 'D:\MyWorkspace\PythonWorkspace\scrapy_learn\img' #圖片存儲(chǔ)目錄
# 30天的圖片失效期限
IMAGES_EXPIRES = 30
八. 遇到的問(wèn)題
- 爬取圖片的時(shí)候,沒(méi)有辦法爬取其他設(shè)置的item
解決:
爬取圖片,寫items.py文件的時(shí)候,一定要寫這三行
image_urls = scrapy.Field() #圖片鏈接
image = scrapy.Field() #圖片
image_paths = scrapy.Field() #圖片路徑
- 爬取圖片時(shí),只能爬取帶圖片的老師的信息
解決:
將TutorImagePipeline類中 item_completed函數(shù)中這兩行注釋掉:
# if not image_paths:
# raise DropItem("Item contains no images")
這兩行的意思是,這一整個(gè)item如果沒(méi)有圖片的話,則丟掉整個(gè)item。所以才會(huì)導(dǎo)致沒(méi)有圖片的老師信息爬取不到。
- 環(huán)境問(wèn)題
安裝和運(yùn)行scrapy的過(guò)程中會(huì)遇到很多環(huán)境上的問(wèn)題,這是因?yàn)橄鄳?yīng)的依賴沒(méi)有安裝好。這個(gè)時(shí)候就需要查看錯(cuò)誤信息,然后利用百度、谷歌去搜索相應(yīng)的依賴應(yīng)該如何安裝。
九. 運(yùn)行爬蟲(chóng)及爬取結(jié)果
當(dāng)代碼編寫無(wú)誤后,在命令行界面中,進(jìn)入項(xiàng)目文件夾,即scrapy_learn目錄下,運(yùn)行以下代碼即可開(kāi)始爬蟲(chóng)。
scrapy crawl tutor -o tutor.json
以上代碼是運(yùn)行爬蟲(chóng),并將爬取的內(nèi)容保存為json格式的文件。
爬取結(jié)果:

tutor.json
爬取照片:

爬取教師照片
