Python編寫網頁爬蟲爬取oj上的代碼信息

 OJ升級,代碼可能會丟失. 所以要事先備份. 一開始傻傻的複製粘貼, 後來實在不能忍, 得益於大瀟的啓發和聰神的原始代碼, 網頁爬蟲走起!


 已經有段時間沒看Python, 這次網頁爬蟲的原始代碼是 python2.7版本, 試了一下修改到3.0版本, 要做很多包的更替,感覺比較煩,所以索性就在這個2.7版本上完善了.


 首先觀賞一下原始代碼,我給加了一些註釋:

 

# -*- coding: cp936 -*-

import urllib2
import urllib
import re
import thread
import time
import cookielib

cookie_support = urllib2.HTTPCookieProcessor(cookielib.CookieJar())
opener = urllib2.build_opener(cookie_support,urllib2.HTTPHandler)
urllib2.install_opener(opener)

# 下面是正則表達式部分,意在過濾爬取頁面的標籤信息
class Tool:
    A = re.compile(" \;")                           #A-J對標籤進行匹配
    B = re.compile("\<BR\>")
    C = re.compile("<\;")
    D = re.compile(">\;")
    E = re.compile(""\;")
    F = re.compile("&")
    G = re.compile("Times\ New\ Roman\"\>")
    H = re.compile("\</font\>")
    I = re.compile("'")
    J = re.compile(r'語言.*?face=')
    def replace_char(self,x):                      #將標籤內容替換成目標內容
        x=self.A.sub(" ",x)
        x=self.B.sub("\n\t",x)
        x=self.C.sub("<",x)
        x=self.D.sub(">",x)
        x=self.E.sub("\"",x)
        x=self.F.sub("&",x)
        x=self.G.sub("",x)
        x=self.H.sub("",x)
        x=self.I.sub("\'",x)
        x=self.J.sub("",x)
        return x

class HTML_Model:
    def __init__(self,u,p):
        self.userName = u                 #用戶名和密碼等登入信息
        self.passWord = p
        self.mytool = Tool()
        self.page = 1                      #從代碼頁的第一頁開始爬
        self.postdata = urllib.urlencode({
            'userName':self.userName,
            'password':self.passWord
})
    def GetPage(self):
        myUrl = "http://acm.njupt.edu.cn/acmhome/login.do"
        #請求包括網址和登入表單
        req=urllib2.Request(                       
            url = myUrl,
            data = self.postdata
            )
        #此次相應爲打開這個url
        myResponse = urllib2.urlopen(req)
        #讀取頁面
        myPage = myResponse.read()
        flag = True
        #當flag爲true時 繼續抓取下一頁
        while flag:
            #下一頁網址
            myUrl="http://acm.njupt.edu.cn/acmhome/showstatus.do?problemId=null&contestId=null&userName="+self.userName+"&result=1&language=&page="+str(self.page)
            #print(myUrl)
            myResponse = urllib2.urlopen(myUrl)
            #打開下一頁的頁面
            myPage = myResponse.read()
            #正則表達式搜索是否還有下一頁,更新flag. 原理爲在當前頁查找, 如果當前頁面有提交的代碼,則含有類似"<a href="/acmhome/solutionCode.do?id=4af76cc2459a0dd30145eb3dd1671dc5" target="_blank">G++</a>" 這樣的標籤. 也就是說如果我的代碼只有84頁,那麼則在第85頁flag-false,不再訪問86頁
            st="\<a\ href\=.*?G\+\+"
            next = re.search(st,myPage)
            #print(st)
            print(next)
            if next:
                flag=True
                print("True")
            else:
                flag=False
                print("False")
            #print(myPage)
           #找到當前頁面下所有題目代碼的連接,放在myItem這個list中
            myItem = re.findall(r'<a href=\"/acmhome/solutionCode\.do\?id\=.*?\"\ ',myPage,re.S)
            for item in myItem:
                #print(item)
 
               #對於每個題目代碼連接,訪問其所在頁面
                url='http://acm.njupt.edu.cn/acmhome/solutionCode.do?id='+item[37:len(item)-2]
                #print(url)
                myResponse = urllib2.urlopen(url)
                myPage = myResponse.read()
                mytem = re.findall(r'語言.*?</font>.*?Times New Roman\"\>.*?\</font\>',myPage,re.S)
                #print(mytem)
                sName = re.findall(r'源代碼--.*?</strong',myPage,re.S)
                #sName = sName[2:len(sName)]
                for sname in sName:
                    print(sname[2:len(sname)-8])
                    # sname中包含了題號信息
                    f = open(sname[2:len(sname)-8]+'.txt','w+')
                    #通過前面的標籤過濾函數,將過濾後的代碼寫在文件裏
                    f.write(self.mytool.replace_char(mytem[0]))
                    f.close()
                    print('done!')
            self.page = self.page+1

print u'plz input the name'
u=raw_input()
print u'plz input password'
p=raw_input()
#u = "B08020129"
#p = *******"
myModel = HTML_Model(u,p)
myModel.GetPage()

現在這個代碼有兩個問題:

首先,在標籤匹配的時候沒有支持多行,也就是爬下來的代碼中仍然包含跨度多行的標籤, 純代碼仍然需要人工提取.

第二,因爲代碼頁面並沒有問題的題目信息,所以僅以題號作爲文件名. 這樣若果升級後的OJ題目順序發生改變, 將無法將題目與代碼進行對應.


針對第一個問題, 修正的方法比較簡單:

      在正則表達式匹配的時候, 將第二個參數位置加上re.DOTALL即可.

     例如:

      J = re.compile(r'語言.*?face=',re.DOTALL)


對於第二個問題, 可以根據題號尋找題目的頁面(而非此前代碼的頁面), 然後從題目頁面中提取標題信息.


在題目頁面中,我發現只有標題是用<strong><\strong> 標籤修飾的,所以可以這樣匹配

sName2=re.findall(r'<strong>([^<]+)</strong>',myPage2,re.S)


另外文件命名的時候不可以有空格,所以還要濾除空格

sname2=sname2.replace(" ","")


即使這樣,有時在創建文件時仍然會拋出異常, 但是重新執行一次可能就會不再出現問題.


下面是晚上後的代碼, 修改的地方加粗了.


# -*- coding: cp936 -*-

import urllib2
import urllib
import re
import thread
import time
import cookielib

cookie_support = urllib2.HTTPCookieProcessor(cookielib.CookieJar())
opener = urllib2.build_opener(cookie_support,urllib2.HTTPHandler)
urllib2.install_opener(opener)


class Tool:
    A = re.compile(" \;")
    B = re.compile("\<BR\>")
    C = re.compile("<\;")
    D = re.compile(">\;")
    E = re.compile(""\;")
    F = re.compile("&")
    G = re.compile("\"Times\ New\ Roman\"\>")
    H = re.compile("\</font\>")
    I = re.compile("'")
    J = re.compile(r'語言.*?face=',re.DOTALL)
    def replace_char(self,x):
        x=self.A.sub(" ",x)
        x=self.B.sub("\n\t",x)
        x=self.C.sub("<",x)
        x=self.D.sub(">",x)
        x=self.E.sub("\"",x)
        x=self.F.sub("&",x)
        x=self.G.sub("",x)
        x=self.H.sub("",x)
        x=self.I.sub("\'",x)
        x=self.J.sub("",x)
        return x

class HTML_Model:
    def __init__(self,u,p):
        self.userName = u
        self.passWord = p
        self.mytool = Tool()
        self.page = 81
        self.postdata = urllib.urlencode({
            'userName':self.userName,
            'password':self.passWord
})
    def GetPage(self):
        myUrl = "http://acm.njupt.edu.cn/acmhome/login.do"
        req=urllib2.Request(
            url = myUrl,
            data = self.postdata
            )
        myResponse = urllib2.urlopen(req)
        myPage = myResponse.read()
        flag = True
        while flag:
            myUrl="http://acm.njupt.edu.cn/acmhome/showstatus.do?problemId=null&contestId=null&userName="+self.userName+"&result=1&language=&page="+str(self.page)
            #print(myUrl)
            myResponse = urllib2.urlopen(myUrl)
            myPage = myResponse.read()
            st="\<a\ href\=.*?G\+\+"
            next = re.search(st,myPage)
            #print(st)
            print(next)
            if next:
                flag=True
                print("True")
            else:
                flag=False
                print("False")
            #print(myPage)
            myItem = re.findall(r'<a href=\"/acmhome/solutionCode\.do\?id\=.*?\"\ ',myPage,re.S)
            for item in myItem:
                #print(item)
                url='http://acm.njupt.edu.cn/acmhome/solutionCode.do?id='+item[37:len(item)-2]
                #print(url)
                myResponse = urllib2.urlopen(url)
                myPage = myResponse.read()
                mytem = re.findall(r'語言.*?</font>.*?Times New Roman\"\>.*?\</font\>',myPage,re.S)
                #print(mytem)
                sName = re.findall(r'源代碼--.*?</strong',myPage,re.S)
                #sName = sName[2:len(sName)]
                
                
                for sname in sName:
                    url2="http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id="+sname[8:len(sname)-8]
                    myResponse2=urllib2.urlopen(url2)
                    myPage2=myResponse2.read();
                    

                    sName2=re.findall(r'<strong>([^<]+)</strong>',myPage2,re.S)
                    sname2=sName2[0]
                    sname2=sname2.replace(" ","")
                   # print(sName)
                    print(sname[8:len(sname)-8]+'.'+sname2[0:len(sname2)])
                    f = open(sname[8:len(sname)-8]+'.'+sname2[0:len(sname2)]+'.txt','w+')
                    f.write(self.mytool.replace_char(mytem[0]))
                    f.close()
                    print('done!')

            print(self.page)
            self.page = self.page+1

#print u'plz input the name'
#u=raw_input()
#print u'plz input password'
#p=raw_input()
u = "LTianchao"
p = "******"
myModel = HTML_Model(u,p)
myModel.GetPage()





關於Python的網頁爬取問題,這只是一個很簡單的demo, 下面還需要深入學習.(如果有時間的話)

發佈了134 篇原創文章 · 獲贊 3 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章