爬取所有教师信息

此篇主要有

1、XPath解析库的应用

2、re正则表达式的应用

3、selenium的应用,以及无窗口运行。

4、post请求

5、pyinstaller生成exe文件->https://www.cnblogs.com/albert-yzp/p/10186561.html

这个程序是爬去西电所有老师的基本信息   主页:https://faculty.xidian.edu.cn/

源代码:

import requests#这个库用来获取网页内容
from lxml import etree#这个库用来解析网页内容,方便提取需要的信息
import re#这个库用来正则匹配,也是用来提取需要的信息。
import pandas as pd#这个库是用来处理数据,主要为了提取出点赞数前十的老师

#此函数用来获取学院的名字,链接。
#输入:主页urlhttps://faculty.xidian.edu.cn/
#输出:一个字典,key为学院名字,value为不同学院的url链接。
def get_academies(url):
    response=requests.get(url)#获取网页内容
    XpathAnalyze=etree.HTML(response.text)#解析网页结构
    urls=XpathAnalyze.xpath('/html/body/div[6]/div/div/div[2]/ul[1]/li[*]/a/@href')#获取所有学院的链接
    names=XpathAnalyze.xpath('/html/body/div[6]/div/div/div[2]/ul[1]/li[*]/a/@title')#获取所有学院的名字
    academies = {}#此字典用来完整的保存学院的名字,链接信息。
    for i in range(len(names)):
        academies[names[i]] = urls[i + 1]#遍历所有学院,组成字典
    return academies  #将字典返回

#此函数用来获取学院老师的总页数
#输入:学院的url
#输出:int型数字,学院老师的总页数
def get_page_total_numbers(url):
    response = requests.get(url)#获取学院主页内容
    totalNumbers = re.search('totalpage=(\d+)&PAGENUM=', response.text)#利用正则表达式找到总页数
    return int(totalNumbers.group(1))#返回int型总页数

#此函数用来获取一页中所有老师的url
#输入:一页的url
#输出:此页中所有老师主页的url
def get_all_teachers(url):
    response = requests.get(url)#获取当前页的网页内容
    XpathAnalyze = etree.HTML(response.text)#解析网页
    return XpathAnalyze.xpath('/html/body/div[5]/div/div/div[3]/ul/li[*]/a/@href')#找到所有老师主页的url并返回

#此函数用来提取老师主页的点击次数
#输入:老师主页的网页内容
#输出:字符串,老师主页的点击次数
def get_times(resoposeText):
    account_homepageid=re.search(r"account':'(\d+)','homepageid':(\d+),",resoposeText)#提取post表单所需要的信息
    data={      #构建post表单,因为老师主页的点击次数是js动态获取的,所以必须用post才能获取到。
        'basenum': 0,
        'len': 10,
        'type': 'homepage_total',
        'account': 0,
        'homepageid': 0,
        'ac': 'getHomepageClickByType',
        }
    if account_homepageid: #此处加个判断,因为可能上面没找到post表单所需要的信息
        data['account']=int(account_homepageid.group(1))#找到了才正常把表单信息补充完整
        data['homepageid']=int(account_homepageid.group(2))
    response=requests.post('https://faculty.xidian.edu.cn/system/resource/tsites/click.jsp',data=data)#提交post请求
    return response.text[10:20].lstrip('0')#提取出返回信息中的老师主页的点击次数并返回

#此函数用来获取老师主页中所有的基本信息
#输入:老师主页的url
#输出:字典,老师的基本信息
def get_teacher_detail(url):
    try:#捕捉异常,因为在调试的过程中发现,此处获取老师主页内容的时候会抛出异常
        response = requests.get(url)#获取老师主页网页内容
    except requests.exceptions.ChunkedEncodingError:#如果出现异常,就重新进入这个函数,反复重试。相当于点刷新
        return get_teacher_detail
    response.encoding = 'utf-8'#修改网页字符编码为'utf-8',因为Python默认'utf-8',不修改的话或显示乱码。
    times = get_times(response.text)#调用上面的函数获取老师主页点击次数
    XpathAnalyze = etree.HTML(response.text)#解析网页
    name = XpathAnalyze.xpath('/html/body/div[2]/div/div[3]/div[1]/div[1]/div[1]/span/text()')#提取老师姓名
    details = []#这个列表用来储存所有获取到的老师基本信息
    for i in range(1, 16):#因为老师的基本信息最多可以有15个,所以,我循环获取15次,能保证获取到所有老师信息
        detail = temp = XpathAnalyze.xpath('/html/body/div[2]/div/div[3]/div[1]/div[2]/div/p[' + str(i) + ']/text()')#获取老师的基本信息
        if detail:#如果成功的获取到了
            detail = detail[0].replace('\n', '')#去除所有换行符
            detail = detail.replace(' ', '')#去除所有空格
            details.append(detail)#添加到上面新建的列表中
    detailsResult = {#此字典用来统一保存老师的所有基本信息,如果某项基本信息没有,就置为空。
        '姓名': '',
        '职称': '',
        '性别': '',
        '出生年月': '',
        '毕业院校': '',
        '学历': '',
        '学位': '',
        '在职信息': '',
        '所在单位': '',
        '入职时间': '',
        '所属院系': '',
        '职务': '',
        '学科': '',
        '办公地点': '',
        '联系方式': '',
        '点击次数': ''}
    if name:#如果成功获取到了老师姓名
        detailsResult['姓名'] = name[0]#报存到字典中
    if details:#如果成功获取到了其他基本信息
        detailsResult['职称'] = details[0]#保存职称,(因为第一个肯定为职称,所以直接赋值)
    detailsResult['点击次数'] = times.lstrip('0')#保存点击次数
    for detail in details[1:]:#报错其他基本信息
        split = detail.find('')#获取key,value的分割点
        detailsResult[detail[:split]] = detail[split + 1:]#保存到字典
    return detailsResult#将此老师基本信息返回

#主函数开始
#函数从此处开始运行,上面相当于声明函数。
mainUrl='https://faculty.xidian.edu.cn/'#这个是网站的主页url。
baseStr='totalpage={}&PAGENUM={}&'#这个字符串为了方便构建不同页数的网址,相当于翻页
comma=','#这个字符串为了方便保存csv文件时使用

allAcademies=get_academies(mainUrl)#调用函数获取所有学院名字与url
for name,url in allAcademies.items():#遍历所有学院
    if name=='电子工程学院':#这个是为了只爬电院,如果想爬整个学校,这一行注释即可。
        nowTeacherNumber=1#这个变量用来保存爬到第几个老师了
        academiesUrl=mainUrl+url#此学院主页的url
        totalPageNumbers=get_page_total_numbers(academiesUrl)#调用函数获取学院教师的总页数
        with open(name+'.csv','w') as f:#打开csv文件,用来保存爬取到的所有老师的信息,以学院名命名
            for pageNumber in range(1,totalPageNumbers+1):#遍历所有页数
                pageUrl=academiesUrl[:41]+baseStr.format(str(totalPageNumbers),str(pageNumber))+academiesUrl[41:]#不同页数的url
                print('正在爬取' + name + '' + str(pageNumber) + '页:', pageUrl)#打印状态信息,正在爬取哪个学院第几页
                allTeachersUrls=get_all_teachers(pageUrl)#调用函数获取到当前页的所有老师的url
                for teacherUrl in allTeachersUrls:#遍历当前所有老鼠的的url
                    print('正在爬取' + name + '' + str(nowTeacherNumber) + '位老师:',teacherUrl)#输出状态信息,正在爬取哪个学院第几个老师
                    teachersdetails=get_teacher_detail(teacherUrl)#调用函数获取老师的基本信息
                    if(nowTeacherNumber==1):
                        f.write(comma.join(teachersdetails.keys())+'\n')#csv文件第一行保存的是’姓名职称等’这一列保存的什么信息
                    if(teachersdetails['姓名']):
                        f.write(comma.join(teachersdetails.values()) + '\n')#保存该老师的所有基本信息
                    nowTeacherNumber=nowTeacherNumber+1#正在爬取第几个老师数加1


print("数据爬取完成,接下来对点击次数进行排序")
for academy in allAcademies.keys():#遍历所有学院
    if academy == '电子工程学院':#这一个也是,为了值处理电院,如果想处理所有学院,把这一行注释掉
        academyData=pd.read_csv(open(academy+'.csv'),error_bad_lines=False)#读取csv文件的所有老师信息
        academyData_Sorted = academyData.sort_values(by='点击次数', ascending=False)#按照点击次数排序
        academyData_Sorted.to_csv(academy+'(sorted).csv', index=False, sep=',', encoding="gbk")#将排序完的数据也保存为csv文件,命名为学院名称加(sorted)
        print(academy+'点击次数前10位老师')
        for i in range(10):#打印输出点击次数前十位老师
            print(''+str(i+1),'名:',academyData_Sorted.iloc[i]['姓名'], academyData_Sorted.iloc[i]['点击次数'])

while(input("输入exit退出")!='exit'):
    continue

1、re的使用

account_homepageid=re.search(r"account':'(\d+)','homepageid':(\d+),",resoposeText)

(1)\d+是匹配多个数字

(2)用account_homepageid.groups()访问匹配到的结果

(3)re.search()是匹配第一个,re.findall()是匹配所有符合的结果。参数是差不多的。

2、XPath的使用

from lxml import etree
XpathAnalyze = etree.HTML(response.text)#解析网页
XpathAnalyze.xpath('/html/body/div[5]/div/div/div[3]/ul/li[*]/a/@href')#寻找需要的内容

 

用这个模板,能爬取绝大部分静态网页内容

3、selenium的使用

from selenium import webdriver

option = webdriver.ChromeOptions()
option.add_argument('headless')#option 是用来设置不弹出chrome界面的
driver = webdriver.Chrome(chrome_options=option)
driver.get(url)
response = driver.page_source#获得动态加载后的网页源代码
#在进行解析就行了
XpathAnalyze = etree.HTML(response)
#不过driver有自己的CSS选择器,不太好记,我也就没用

 

selenium能解决几乎所有动态加载的的网页,完全能做到看到什么爬什么。

但是selenium确实运行太慢了。。。。所以还是要优先考虑分析网络请求。看看有没有动态加载的包储存的是我们需要的内容

下面的post请求就是一种获取动态加载内容的方法

4、post请求

data={      #构建post表单,因为老师主页的点击次数是js动态获取的,所以必须用post才能获取到。
        'basenum': 0,
        'len': 10,
        'type': 'homepage_total',
        'account': 0,
        'homepageid': 0,
        'ac': 'getHomepageClickByType',
        }
response=requests.post('https://faculty.xidian.edu.cn/system/resource/tsites/click.jsp',data=data)#提交post请求

 

1、找到需要的内容所在的位置

2、分析请求

 

3、可以看到是向一个固定的网站提交post请求

查看post表单,就是上面代码里的data

4、经分析不同教师主页的post表单,发现只是account以及homepageid不一样。

而这两个参数可以在教师主页的源代码里的js里的找到

将他们提取出来赋值再提交post请求就可以获得自己想要的内容啦

 

这个程序是给别人写的,花了半天多点的时间赚了50块钱,虽然有点少,但是我也学到了很多东西。也是我第一次用写代码赚钱哦。

posted @ 2018-12-28 11:38  Albert-YZP  阅读(1459)  评论(1编辑  收藏  举报