首页 > 代码库 > Python编写网页爬虫爬取oj上的代码信息

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 = http://www.mamicode.com/urllib.urlencode({>
        #请求包括网址和登入表单
        req=urllib2.Request(                       
            url = myUrl,
            data = http://www.mamicode.com/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=http://www.mamicode.com/"/acmhome/solutionCode.do?id=4af76cc2459a0dd30145eb3dd1671dc5" target="_blank">G++" 这样的标签. 也就是说如果我的代码只有84页,那么则在第85页flag-false,不再访问86页>
           #找到当前页面下所有题目代码的连接,放在myItem这个list中
            myItem = re.findall(r‘<a href=http://www.mamicode.com/"/acmhome/solutionCode/.do/?id\=.*?\"\ ‘,myPage,re.S)>
 
               #对于每个题目代码连接,访问其所在页面
                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 = http://www.mamicode.com/urllib.urlencode({> 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, 下面还需要深入学习.(如果有时间的话)