同学拿出一个需求:从某课程教学网站上爬取所有课程的主页面,以及课程简介栏目内容。
于是在之前做的那个练手级的Python爬虫程序中进行修改,最终实现了该功能。与之前那个爬虫不同,这里每一个大类的课程下面都有上千个具体课程名,分为几百页,所以需要识别翻页的问题。
另外,由于网站结构不同,这里的程序整体实现思路也稍有不同,大致如下:
1、从该网站首页获取所有课程大类的链接放到list中
2、遍历上述list,对于每一个链接,对应的都是具体课程名的列表,24个为一页。
2.1 获取该页面中包含的具体课程地址链接,并读取出具体内容,将相关信息保存到本地txt文件中;
2.2 是否有‘下一页’链接。如果有,将此‘下一页’的链接设置为当前页,交给循环进行迭代;如果没有,说明该大类已经读取完毕,继续外层循环
具体代码:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import time
#所需变量初始化及准备工作
#记录程序开始时间
start = time.clock()
#设置网站首页地址
rooturl='http://www.jingpinke.com/'
#创建一个list用于保存课程大类的链接地址
indexlist=[]
##====================以下为方法========================##
'''
方法名:getContent
作用:从pagelist中的url中解析出相关内容,并保存到本地文本中
参数:含有具体课程内容的网址
'''
def getContent(url):
try:
currentPage=urlopen(url).read() #读取源码
except Exception as err:
print('联网超时,退出当前页面。')
currentText=BeautifulSoup(currentPage) #利用bs进行解析
#获取课程标题、时间、教师等信息,并将它们以空格连接起来作为文件名使用
title=currentText.find('div',{'class':'cTitle'}).find('h2').get_text()
teacher=currentText.find('div',{'class':'course_final_ohter'}).findAll('span')[0].get_text()
university=currentText.find('div',{'class':'course_final_ohter'}).findAll('span')[1].get_text()
date=currentText.find('div',{'class':'course_final_ohter'}).findAll('span')[2].get_text()
rank=currentText.find('div',{'class':'course_final_ohter'}).findAll('span')[3].get_text()
classtitle=date+' '+university+' '+rank+' '+title+' '+teacher
#获取课程简介内容
briefintro=currentText.find('pre').get_text()
#以标题为文件名,创建txt文件,并写入正文内容
f=open('file/'+classtitle+'.txt','w+', encoding='utf-8')
f.write(classtitle+'\r\n'+briefintro)
print(classtitle+'.txt')
f.close()
#开始爬取
# 1、先解析根目录,获取13个目标链接
print('解析根目录')
rawtext=urlopen(rooturl).read()
soup = BeautifulSoup(rawtext)
targetDiv=soup.find('div',{'class':'benke_fenlei'})
catalogLinks=targetDiv.findAll('a')
for l in catalogLinks:
indexlist.append(l.get('href'))
print('根目录解析完成')
#2、从indexlist中逐个读取地址,获取该课程大类下的每个课程的地址
for index in indexlist:
currentpage=index #初始时,将某大类的链接设为当前页
count=1 # 计数器,计算某大类下的课程数目
while True:
print("当前页:"+currentpage)
try:
rawtext=urlopen(currentpage).read() #读取当前页
except Exception as err:
print('联网超时,退出当前大类。')
break
soup= BeautifulSoup(rawtext) #解析当前页
eachclass=soup.find('div',{'class':'course_list'}).findAll('table') #获取课程名列表,每一个课程名都放在一个table中
for c in eachclass: #循环获取每一个课程的链接地址
print(str(count)+':http://course.jingpinke.com'+c.find('a').get('href')) #打印该地址
count=count+1 # 计数器自增
getContent('http://course.jingpinke.com'+c.find('a').get('href')) #调用getContent方法,获取该页内容,并保存
if soup.find(id='nextPage')==None: # 如果当前页未发现下一页链接 说明该大类已经获取完毕
print('没有了。') # 打印结束
break #退出外层循环,继续下一大类
else: #否则,说明还有下一页
nextpageurl='http://course.jingpinke.com/search'+soup.find(id='nextPage').find('a').get('href') # 获取当前页中的下一页链接
currentpage=nextpageurl #将当前页中的下一页链接设为当前页
print('下一页:'+nextpageurl) # 打印下一步要处理的地址
#4、计算程序执行过程耗时
end = time.clock()
print (end-start)
说明:
由于我是在sublime text2环境下写的程序,之前将该软件默认的字符编码设为gbk,这导致写入的文件名中含有非中文字符(比如阿拉伯文)时,出现gbk不能编译的错误,后来在csdn论坛上看到,如果 在操作系统的环境变量中加入PYTHONIOENCODING项,项值为utf-8,其含义是将Python的默认IO编码设置为utf-8,然后将sublime text2中的pyton.sublim-build中人为添加的endoding:gbk删掉,重启sublime text2后,即可解决上述问题。