python爬蟲——爬取知網體育學刊引證論文資訊
阿新 • • 發佈:2019-02-09
前言
國慶百無聊賴,然後幫一個小姐姐爬取知網資訊,覺得知網算目前處理過的對爬蟲稍微有點防範的網站,遂有了這篇部落格
目標
爬取知網上2003年體育學刊文獻所有論文的引證論文,包括論文名稱、作者、發表時間,也就是下面紅框所指處
點選click處,點選黑框,紅框所指處即為要爬取資料:
分析
- 知網主體頁面使用ASP(不知道啥東西,類似於jsp一樣的模板吧),我需要爬取的頁面後臺是通過模板解析後返回html頁面,所以不可能捕獲介面獲得json
- 知網會有iframe,不過沒有巢狀,iframe可以在html中巢狀html,問過前端同學後,才知道這是兩個html檔案,瀏覽器會把兩個html巢狀顯示,iframe在一定程度上會增加爬取難度,一般iframe的src屬性會標記html檔案的url,但是知網的不是,可能是js處理過的,抓包顯示url不是src屬性的值
- 知網會用cookie跟蹤使用者行為
- 第一幅圖中,click處的url貌似是經過js處理,直接請求,會出現重定向,返回到知網首頁
難點
- 知網採用cookie跟蹤使用者行為以及部分url經過js處理,所以我決定使用selenium+chromedriver,但是太慢了,而且有點佔資源,這裡知網有個小漏洞,引證論文頁面不需要cookie,所以第一遍使用selenium+chromedriver處理獲得所有引證論文url(一共299個),第二遍使用urllib+etree單獨處理引證論文(一共6800+)
- 引證論文存在翻頁,但是翻頁後大量資料會有重複,並且頁面形式不固定,例如某些頁面有A、B、C三處有引證論文,有些頁面有A、B、C、D、E五處引證論文,具體參見知網頁面,這裡考慮到程式健壯性,我選擇每次插入資料前先查一遍資料是否存在(有點蠢),雖然可以使用資料庫的unique欄位,但是異常丟擲太頻繁
程式碼
獲得引證論文url
from selenium import webdriver import time from lxml import etree from urllib import request from dbmanager_zhiwang import dbmanager_paper def get_paper(page,index): html_parse=etree.HTML(page) ul=html_parse.xpath('//div[@class="essayBox"]/ul')[index] li_list=ul.findall('li') for li in li_list: a_list=li.findall('a') for index in range(0,len(a_list)): print(a_list[index].text) if index==0: print(a_list[index].tail) def get_cookie(): driver.get('http://kns.cnki.net/kns/brief/default_result.aspx') time.sleep(5) driver.find_element_by_name('txt_1_value1').send_keys('體育學刊') driver.find_element_by_xpath('//select[@id="txt_1_sel"]//option[@value="LY$%=|"]').click() driver.find_element_by_id('btnSearch').click() time.sleep(5) #缺少paperid def get_url(num): elements=driver.find_elements_by_xpath('//table[@class="GridTableContent"]//tr[@bgcolor]') for element in elements: try: a=element.find_element_by_xpath('td/a[@class="fz14"]') print(a.get_attribute('href')) paper_info=element.text.replace('\n',' ').split(' ') paper_title=paper_info[1] index=2 author='' while('體育學刊' not in paper_info[index]): author=author+paper_info[index] index=index+1 date=paper_info[index+1] reference=paper_info[index+3] insert_info=(str(num),paper_title,author,date,reference,a.get_attribute('href')) a.click() windows = driver.window_handles driver.switch_to.window(windows[-1]) time.sleep(5) i=0 while(i<5): i=i+1 if(etree.HTML(driver.page_source).xpath('//div[@class="yzwx"]/a')!=[]): break #不存在引證論文 url0_list=[] url1_list=[] url2_list=[] if(i!=5): html_parse=etree.HTML(driver.page_source) url=driver.find_element_by_xpath('//div[@class="yzwx"]/a').get_attribute('href') if(url!=None): print(url) driver.get(url) html_parse=etree.HTML(driver.page_source) a0_list=html_parse.xpath('//span[@id="CJFQ"]//a') a1_list=html_parse.xpath('//span[@id="CDFD"]//a') a2_list=html_parse.xpath('//span[@id="CMFD"]//a') for a in a0_list: url0_list.append(a.attrib['href']) for a in a1_list: url1_list.append(a.attrib['href']) for a in a2_list: url2_list.append(a.attrib['href']) db.insert_info(insert_info,url0_list,url1_list,url2_list) num=num+1 except Exception as arg: print (arg) driver.close() driver.switch_to_window(windows[0]) time.sleep(5) return num if __name__=="__main__": options = webdriver.ChromeOptions() prefs = { 'profile.default_content_setting_values' : { 'notifications' : 2 } } options.add_experimental_option('prefs',prefs) driver = webdriver.Chrome(chrome_options = options) driver.maximize_window() get_cookie() db=dbmanager_paper('root','12345','127.0.0.1','zhiwang') num=0 now_page=1 driver.get('http://kns.cnki.net/kns/brief/brief.aspx?ctl=4a7fde68-1a44-4852-8b23-1a70aeb4cf8b&dest=%E5%88%86%E7%BB%84%EF%BC%9A%E5%8F%91%E8%A1%A8%E5%B9%B4%E5%BA%A6%20%E6%98%AF%202003&action=5&dbPrefix=SCDB&PageName=ASP.brief_default_result_aspx&Param=%e5%b9%b4+%3d+%272003%27&SortType=(FFD%2c%27RANK%27)+desc&ShowHistory=1&isinEn=1') while(now_page<16): num=get_url(num) a_list=driver.find_elements_by_xpath('//div[@class="TitleLeftCell"]//a') for a in a_list: if(a.text=='下一頁'): a.click() break now_page=now_page+1 time.sleep(5)
獲得引證論文
from selenium import webdriver
import time
from lxml import etree
from urllib import request
import re
from dbmanager_zhiwang import dbmanager_paper
def get_paper(url,paperid):
req=request.Request(url,headers=header)
html_page=request.urlopen(req).read().lower().decode('utf-8',errors='ignore')
html_parse=etree.HTML(html_page)
ul_list=html_parse.xpath('//div[@class="essaybox"]//ul')
for ul in ul_list:
li_list=ul.findall('li')
for li in li_list:
try:
a_list=li.itertext()
info_temp=''
for a in a_list:
info_temp=info_temp+a.replace(' ','').replace('\r\n','').replace('  ','')
info=info_temp.split('.')
if(db.judge_exist(info[0])==False):
length=len(info)-1
if(length<3):
deal=info[length]
date=re.findall('\d.*',deal)[0]
workunit=deal.replace(date,'').replace('年','')
info[length]=workunit
info.append(date)
info.append(str(paperid))
if(db.insert_paper_info(tuple(info))==False):
return False
except Exception as arg:
print(arg)
return False
return True
if __name__=="__main__":
header={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
db=dbmanager_paper('root','Ll41655184165518','127.0.0.1','zhiwang')
while(True):
status='finish'
result=db.get_url()
if(result==[]):
break
print(result[2])
if(get_paper(result[2],result[1])==False):
status='error'
status_info=(status,result[0])
db.set_status(status_info)
time.sleep(10)
最後把資料庫中的資料轉換為excel,部落格中沒有給出資料庫結構,詳情見gayhub(沒有打錯):https://github.com/zhuoyunli/crawler_zhiwang,裡面有資料庫檔案以及處理好的excel檔案