Python爬虫实战

智立方爬虫实战

1.     概述

智立方是一个展示科研人员用户画像的一个平台,本次爬虫任务即是爬取某一科研人员相关的科研人员的人名,相关作品数供职机构等信息以及该科研人员的资助情况中的项目名称以及相关作品数。最后对该科研人员的项目进行分类,并且分别统计分析得出每一个科研人员的*,省级,市级等项目数。

2.     爬取网站介绍

智立方人物检索页:http://buidea.com:9001/writer/WriterSearch.aspx

Python爬虫实战

图1. 智立方人物检索页

 

智立方人物检索页: http://buidea.com:9001/writer/writersearch.aspx?invokemethod=search&q=%7B“search”%3A“冯建华%20清华大学”%2C“Type”%3A“writer”%7D&

Python爬虫实战

图2.搜索后对应的页面

 

智立方人物检索页http://buidea.com:9001/writer/rw_rw.aspx?id=100000000916663&subid=&showname=&searchtype=

Python爬虫实战

图3.相关人物界面

 

智立方人物检索页http://buidea.com:9001/writer/rw_zp.aspx?id=100000000916663&subid=&showname=&searchtype=

 Python爬虫实战

图4.所获资助

3.     爬取思路分析以及代码实现

(1).代码整体框架

      爬虫代码可整体分为四块,第一部分获取HTML文件部分(可用urllib或者requests),本案例使用requests进行爬取网页。第二部分为解析网页内容提取需要的信息(可用beautifulsoup或者lxml),此案例两者根据需求的不同都有使用。第三部分为文件的输出部分,按照自己的需求可以直接存到数据库中也可存到txt文件中。第四部分及主函数部分,控制着程序的整体框架。

(2). 获取HTML文件

该部分主要采用了一个爬取网页的通用代码框架

# 该函数用Requests库将网页爬取下来
def getHTMLText(url):
   
# 爬取网页的通用代码框架
   
try:
        kv = {
'user-agent':'Mozilla/5.0'}#该参数是设置用浏览器的形式访问网站
       
r = requests.get(url,headers=kv,timeout=30)#爬取网页生成response对象
        r.raise_for_status()
        r.encoding = r.apparent_encoding
#判断是否爬取成功
       
return r.text        #返回爬虫的文本内容
   
except:
       
return ""

(3). 解析网页内容

该部分一共有好几块需要解析

第一部分从输入(姓名+机构)检索后的页面提取一个ID该ID将用于后面构成爬取相关任务与所获资助页面的URL。

Python爬虫实战

图5.获取对应ID页面

代码如下:

def getID(newurl):
    if newurl is None:
        print("html count:", newurl)
        return
    html=getHTMLText(newurl)
    tree = etree.HTML(html) #用lxml来解析网页
    ID=tree.xpath("//div[@class='search_list type_writer']/dl/dt[@class='writer']/a/@href")
    print(ID)
    return ID[0][22:37]#可能会有多个,提取第一个的ID

 

第二部分是获取相关人物页面中,共有多少页的信息,从而可以通过循环构造每一页的URL链接遍历每一页。

Python爬虫实战

图6.获取对应页数页面

代码如下:

#解析网页并获得页码信息
#
因为需要爬取多页信息,所以先获得一共多少页
def getpage(html):
    soup = BeautifulSoup(html
, "html.parser")#用BeatifulSoup库来解析网页
    m = soup.find_all('span',class_="total")#用find_all方法找到包含总页数的那个标签
    if len(m)!=0:
        num=re.sub(
r'\D',"",str(m[0]))#用正则的方式把非数字的部分删除掉
       
return num
   
else:
       
return 0

 

第三部分从获得ID之后,可以构造通往相关任务的URL链接,从这个链接的网页中需要爬取相关人员的名字,相关作品数,供职机构等信息。以及构造所获资助URL链接爬取

Python爬虫实战

图7.获取相关人物个人信息页面

代码如下:

#解析网页信息获得科研人员的相关人员姓名,相关作品数,供职机构
def html_parse(ulist,html,name):
   
if htmlis None:
       
print("html count:",html)
       
return
    try
:
        tree = etree.HTML(html)
        re_people=tree.xpath(
"//div[@class='search_listtype_writer']/dl/dt[@class='writer']/a/text()")#相关人员姓名
        
agency=tree.xpath("//div[@class='search_listtype_writer']/dl/dd[@class='organ hide3 hide2']/text()")#供职机构
       
re_work=tree.xpath("//div[@class='search_listtype_writer']/dl/dt[@class='writer']/span[@class='relative']/a/text()")#相关作品数
       
print(re_people)
       
#把该页的相关信息合并成一个字符串放入ulist
       
for iin range(len(re_people)):
           
#这边这个判断是为了排除有一些人的相关作品是0
           
if len(re_work[i])>=6:
                ulist.append(
str(name)+","+str(re_people[i])+","+str(agency[i][5:])+","+str(re_work[i][6:]))
           
else:
                ulist.append(
str(name) +"," +str(re_people[i]) +"," +str(agency[i][5:])+"," +str(re_work[i]))
   
except:
       
print("error")

']""/a/text()")
       
re_work = tree.xpath(
           
"/html/body/div[@class='bodyobject_writer']/div[@class='main']/div[@class='search']/""div[@class='m']/div[@class='search_listtype_writer']/dl/dt[@class='fund']""/span[@class='relative']/a/text()")
       
print(str(fund))
       
for iin range(len(fund)):
           
if len(re_work) >=6:
                ulist.append(
str(name) +"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i][6:]))
           
else:
                ulist.append(
str(name) +"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i]))
   
except:
       
print("error")

 

Python爬虫实战 

图8.获取所获资助信息页面

代码如下:

#解析网页信息获得科研人员的资助情况
def html_parse(ulist,html,name,university):
   
if htmlis None:
       
print("html count:",html)
       
return
    try
:
       
#这边爬取项目名称时就遇到了一个情况,如果用Xpath有部分较长的内容就分为两个list内容,很难区分
        #所以用BeautifulSoup库提取然后进一步用正则来匹配
        soup = BeautifulSoup(html,"html.parser")
        m = soup.find_all(
'a',href=re.compile("/fund/zz.aspx*"))
        fund = []
       
for iin range(0,len(m),2):
           
if str(m[i].string) !="None":
                fund.append(
str(m[i].string))
           
else:
                dr = re.compile(
r'<[^>]+>',re.S)
                dd = dr.sub(
'',str(m[i]))
               
print(dd)
                fund.append(dd)
        tree = etree.HTML(html)
       
# fund= tree.xpath("/html/body/div[@class='bodyobject_writer']/div[@class='main']/div[@class='search']/""div[@class='m']/div[@class='search_listtype_writer']/dl/dt[@class='fund ']""/a/text()")
       
re_work = tree.xpath(
           
"/html/body/div[@class='bodyobject_writer']/div[@class='main']/div[@class='search']/""div[@class='m']/div[@class='search_listtype_writer']/dl/dt[@class='fund']""/span[@class='relative']/a/text()")
       
print(str(fund))
       
for iin range(len(fund)):
           
if len(re_work) >=6:
                ulist.append(
str(name)+"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i][6:]))
           
else:
                ulist.append(
str(name) +"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i]))
   
except:
       
print("error")

(4). 输出文件内容

该部分的功能即把之前加到list里的字符串输出到txt文件中

#输出文件
def Output(uinfo):
    fout =
open('teacherfund.txt','a',encoding='utf-8')
   
for datainuinfo:
        fout.write(data+
'\n')
    fout.close()

(5)主函数部分

主函数先根据输入文件(冯建华 清华大学)类似这样的一行一行的txt文件,根据然后调用getID()函数,然后根据ID构造成新的URL链接到相应页面获取相关人员的信息或者所获资助情况。其中到了这些页面首先是要调用getpage()函数获取到页数,最后是将文件写入到文件中。

代码如下:

def main():

    queryFile =
open("teacherInfo.txt",'r',encoding='utf-8')
   
# 读取文件中的每一行例如(冯建华 清华大学)搜索获得ID,最后通过该ID组成新的URL
    for queryinqueryFile:
       
# 将输入文件中的每一行分割成导师姓名和学校
       
splitRes = query.split('\t')
       
if len(splitRes) !=2:
           
print(query,' 格式不正确')
       
else:
            uinfo = []
            name = query.split(
'\t')[0]
            university = query.split(
'\t')[1]
            
# new_url = "https://baike.baidu.com/item/"+parse.quote(name)
            #
根据导师姓名和学校构造需要访问的url
           
new_url = "http://buidea.com:9001/writer/writersearch.aspx?invokemethod=search&q=%7B"+ parse.quote("\"") \
                      +
"search" + parse.quote("\"") +"%3A"+ parse.quote("\"") + parse.quote(name) + "%20" \
                      +parse.quote(university) + parse.quote(
"\"") +"%2C"+ parse.quote("\"") + "sType" \
                      + parse.quote(
"\"") +"%3A" + parse.quote("\"") + "writer"+ parse.quote("\"") + "%7D&"
           
print(new_url)
           
#通过该url获得对应的ID
            UrlID=getID(new_url)
           
print(UrlID)
           
#构造这个人需要访问的URL
           
url = "http://buidea.com:9001/writer/rw_rw.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%221%22%7D&&hfldSelectedIds=&"
           
html = getHTMLText(url)
            n =
int(getpage(html))
           
if n!=0:
               
for iin range(1,n + 1):
                    url =
"http://buidea.com:9001/writer/rw_rw.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%22"+str(i)+ "%22%7D&&hfldSelectedIds=&"
                   
new_html = getHTMLText(url)
                    html_parse(uinfo
, new_html,name)
            Output(uinfo)

      

4.     完整代码

(1)   获取相关人物信息代码

#智立方爬取某一老师的相关的科研人员信息
import re
from urllibimportparse
import requests
from bs4 importBeautifulSoup
import bs4
from lxml importetree

# 该函数用Requests库将网页爬取下来
def getHTMLText(url):
   
# 爬取网页的通用代码框架
   
try:
        kv = {
'user-agent':'Mozilla/5.0'}#该参数是设置用浏览器的形式访问网站
       
r = requests.get(url,headers=kv,timeout=30)#爬取网页生成response对象
        r.raise_for_status()
        r.encoding = r.apparent_encoding
#判断是否爬取成功
       
return r.text        #返回爬虫的文本内容
   
except:
       
return ""
#解析网页并获得页码信息
#
因为需要爬取多页信息,所以先获得一共多少页
def getpage(html):
    soup = BeautifulSoup(html
, "html.parser")#用BeatifulSoup库来解析网页
    m = soup.find_all('span',class_="total")#用find_all方法找到包含总页数的那个标签
    if len(m)!=0:
       
print(m[0])
        num=re.sub(
r'\D',"",str(m[0]))#用正则的方式把非数字的部分删除掉
       
print(num)
       
return num;
   
else:
       
return 0;
#解析网页信息获得科研人员的相关人员姓名,相关作品数,供职机构
def html_parse(ulist,html,name):
   
if htmlis None:
       
print("html count:",html)
       
return
    try
:
        tree = etree.HTML(html)
        re_people=tree.xpath(
"//div[@class='search_listtype_writer']/dl/dt[@class='writer']/a/text()")#相关人员姓名
       
agency=tree.xpath("//div[@class='search_listtype_writer']/dl/dd[@class='organ hide3 hide2']/text()")#供职机构
       
re_work=tree.xpath("//div[@class='search_listtype_writer']/dl/dt[@class='writer']/span[@class='relative']/a/text()")#相关作品数
       
print(re_people)
       
#把该页的相关信息合并成一个字符串放入ulist
       
for iin range(len(re_people)):
           
#这边这个判断是为了排除有一些人的相关作品是0
            
if len(re_work[i])>=6:
                ulist.append(
str(name)+","+str(re_people[i])+","+str(agency[i][5:])+","+str(re_work[i][6:]))
           
else:
                ulist.append(
str(name) +"," +str(re_people[i]) +"," +str(agency[i][5:])+"," +str(re_work[i]))
   
except:
       
print("error")
#把list里信息输出到txt文件中
def Output(uinfo):
    fout =
open('output1.txt','a',encoding='utf-8')
   
for datainuinfo:
        fout.write(data+
'\n')
    fout.close()
#解析网页获得对应科研人员的url中的ID
#通过定位该ID可以找到该科研人员各个相关页面
def getID(newurl):
   
if newurlis None:
       
print("html count:",newurl)
       
return
   
html=getHTMLText(newurl)
    tree = etree.HTML(html)
#用lxml来解析网页
    ID=tree.xpath("//div[@class='search_listtype_writer']/dl/dt[@class='writer']/a/@href")
   
print(ID)
   
return ID[0][22:37]#可能会有多个,提取第一个的ID

def main():

    queryFile =
open("teacherInfo.txt",'r',encoding='utf-8')
   
# 读取文件中的每一行例如(冯建华 清华大学)搜索获得ID,最后通过该ID组成新的URL
    for queryinqueryFile:
       
# 将输入文件中的每一行分割成导师姓名和学校
       
splitRes = query.split('\t')
       
if len(splitRes) !=2:
           
print(query,' 格式不正确')
       
else:
            uinfo = []
            name = query.split(
'\t')[0]
            university = query.split(
'\t')[1]
           
# new_url = "https://baike.baidu.com/item/"+parse.quote(name)
            #
根据导师姓名和学校构造需要访问的url
           
new_url = "http://buidea.com:9001/writer/writersearch.aspx?invokemethod=search&q=%7B"+ parse.quote("\"") \
                      +
"search" + parse.quote("\"") +"%3A"+ parse.quote("\"") + parse.quote(name) + "%20" \
                      +parse.quote(university) + parse.quote(
"\"") +"%2C"+ parse.quote("\"") + "sType" \
                      + parse.quote(
"\"") +"%3A" + parse.quote("\"") + "writer"+ parse.quote("\"") + "%7D&"
           
print(new_url)
           
#通过该url获得对应的ID
            UrlID=getID(new_url)
           
print(UrlID)
           
#构造这个人需要访问的URL
           
url = "http://buidea.com:9001/writer/rw_rw.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%221%22%7D&&hfldSelectedIds=&"
           
html = getHTMLText(url)
            n =
int(getpage(html))
           
if n!=0:
               
for iin range(1,n + 1):
                    url =
"http://buidea.com:9001/writer/rw_rw.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%22"+str(i)+ "%22%7D&&hfldSelectedIds=&"
                   
new_html = getHTMLText(url)
                    html_parse(uinfo
, new_html,name)
            Output(uinfo)

main()

 

(2)   获取所获资助信息代码

#智立方爬取某一老师的相关的科研人员信息
import re
from urllibimportparse
import requests
from bs4 importBeautifulSoup
import bs4
from lxml importetree
# 该函数用Requests库将网页爬取下来
def getHTMLText(url):
   
# 爬取网页的通用代码框架
   
try:
        kv = {
'user-agent':'Mozilla/5.0'}#该参数是设置用浏览器的形式访问网站
       
r = requests.get(url,headers=kv,timeout=30)#爬取网页生成response对象
        r.raise_for_status()#判断是否爬取成功
       
r.encoding = r.apparent_encoding
       
return r.text  #返回爬虫的文本内容
   
except:
       
return ""
#解析网页并获得页码信息
#
因为需要爬取多页信息,所以先获得一共多少页
def getpage(html):
    soup = BeautifulSoup(html
, "html.parser")#用BeatifulSoup库来解析网页
    m = soup.find_all('span',class_="total")#用find_all方法找到包含总页数的那个标签
    if len(m)!=0:
        num=re.sub(
r'\D',"",str(m[0]))#用正则的方式把非数字的部分删除掉
       
return num
   
else:
        
return 0
#解析网页信息获得科研人员的资助情况
def html_parse(ulist,html,name,university):
   
if htmlis None:
       
print("html count:",html)
       
return
    try
:
       
#这边爬取项目名称时就遇到了一个情况,如果用Xpath有部分较长的内容就分为两个list内容,很难区分
        #所以用BeautifulSoup库提取然后进一步用正则来匹配
        soup = BeautifulSoup(html,"html.parser")
        m = soup.find_all(
'a',href=re.compile("/fund/zz.aspx*"))
        fund = []
       
for iin range(0,len(m),2):
           
if str(m[i].string) !="None":
                fund.append(
str(m[i].string))
           
else:
                dr = re.compile(
r'<[^>]+>',re.S)
                dd = dr.sub(
'',str(m[i]))
               
print(dd)
                fund.append(dd)
        tree = etree.HTML(html)
       
# fund= tree.xpath("/html/body/div[@class='bodyobject_writer']/div[@class='main']/div[@class='search']/""div[@class='m']/div[@class='search_listtype_writer']/dl/dt[@class='fund ']""/a/text()")
       
re_work = tree.xpath(
           
"/html/body/div[@class='bodyobject_writer']/div[@class='main']/div[@class='search']/""div[@class='m']/div[@class='search_listtype_writer']/dl/dt[@class='fund']""/span[@class='relative']/a/text()")
       
print(str(fund))
       
for iin range(len(fund)):
           
if len(re_work) >=6:
                ulist.append(
str(name) +"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i][6:]))
           
else:
                ulist.append(
str(name) +"," +str(university) +"," +str(fund[i]) +"," +str(re_work[i]))
   
except:
       
print("error")
#输出文件
def Output(uinfo):
    fout =
open('teacherfund.txt','a',encoding='utf-8')
   
for datainuinfo:
        fout.write(data+
'\n')
    fout.close()
#解析网页获得对应科研人员的url中的ID
#通过定位该ID可以找到该科研人员各个相关页面
def getID(newurl):
   
if newurlis None:
       
print("html count:",newurl)
       
return
   
html=getHTMLText(newurl)
    tree = etree.HTML(html)
#用lxml来解析网页
    ID=tree.xpath("//div[@class='search_listtype_writer']/dl/dt[@class='writer']/a/@href")#通过Xpath定位到需要的页面
    print(ID)
   
return ID[0][22:37]

def main():

    queryFile =
open("teacherInfo.txt",'r',encoding='utf-8')
   
#读取文件中的每一行例如(冯建华 清华大学)
   
for queryinqueryFile:
       
# 将输入文件中的每一行分割成导师姓名和学校
       
splitRes = query.split('\t')
       
if len(splitRes) !=2:
           
print(query,' 格式不正确')
       
else:
            uinfo = []
            name = query.split(
'\t')[0]
            university = query.split(
'\t')[1]
           
# new_url ="https://baike.baidu.com/item/"+parse.quote(name)
            #
根据导师姓名和学校构造需要访问的url
           
new_url = "http://buidea.com:9001/writer/writersearch.aspx?invokemethod=search&q=%7B"+ parse.quote("\"") \
                      +
"search" + parse.quote("\"") +"%3A"+ parse.quote("\"") + parse.quote(name) + "%20" \
                      +parse.quote(university) + parse.quote(
"\"") +"%2C"+ parse.quote("\"") + "sType" \
                      + parse.quote(
"\"") +"%3A" + parse.quote("\"") + "writer"+ parse.quote("\"") + "%7D&"
           
print(new_url)
            UrlID=getID(new_url)
           
print(UrlID)
            url =
"http://buidea.com:9001/writer/rw_zz.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%221%22%7D&&hfldSelectedIds=&"
           
print(url)
            html = getHTMLText(url)
            n =
int(getpage(html))
            
if n!=0:
               
for iin range(1,n + 1):
                    url =
"http://buidea.com:9001/writer/rw_zz.aspx?id="+str(UrlID)+"&subid=&showname=&searchtype=&q=%7B%22page%22%3A%22"+str(i)+ "%22%7D&&hfldSelectedIds=&"
                   
new_html = getHTMLText(url)
                    html_parse(uinfo
, new_html,name,university.replace("\n",""))
            Output(uinfo)
main()

 

5.     爬虫结果

(1)   输入文件(部分)

冯建华    清华大学

吴继兰    上海财经大学

姚海龙    清华大学

钱锋       华东理工大学

陈岗       上海财经大学

何高奇    华东理工大学

刘知远    清华大学

阮彤       华东理工大学

韩松乔    上海财经大学

李洪波    清华大学

 

(2)   相关人物信息输出文件(部分)

冯建华,周立柱,清华大学信息科学技术学院计算机科学与技术系,27

冯建华,李国良,清华大学信息科学技术学院计算机科学与技术系,23

冯建华,塔娜,清华大学信息科学技术学院计算机科学与技术系,10

冯建华,张兴,中国工程物理研究院激光聚变研究中心,7

冯建华,叶红飞,北京大学,6

冯建华,李蕾,北京大学,5

冯建华,孙义和,清华大学信息科学技术学院微电子学研究所,5

冯建华,黄维篁,清华大学,5

冯建华,刘喻,清华大学信息科学技术学院计算机科学与技术系,4

冯建华,张鹏,中国科学院,4

冯建华,林腾,北京大学,4

冯建华,钱乾,清华大学,4

(3)所获资助信息输出文件(部分)

冯建华,清华大学,国家自然科学基金,30

冯建华,清华大学,国家重点基础研究发展计划,15

冯建华,清华大学,国家自然科学基金(90207018),8

冯建华,清华大学,国家自然科学基金(60576030),8

冯建华,清华大学,浙江省自然科学基金,7

冯建华,清华大学,浙江省自然科学基金(Y105230),6

冯建华,清华大学,清华大学基础研究基金资助(JCqn2005022),6

冯建华,清华大学,清华大学基础研究基金资助,6

冯建华,清华大学,国家自然科学基金(60573094),4

冯建华,清华大学,国家自然科学基金(61176039),4