yejinru

  网络上大部分关于python爬虫的介绍以及代码讲解,都用的是python2.7或以下版本,用python3.x版本的甚少。

  在python3.3.2版本中,没有urllib2这个库,也没有cookiejar这个库。对应的库分别是http.cookiejar以及urllib这俩。

  关于url以及python2.7爬虫写法的介绍,可以参考[Python]网络爬虫(一):抓取网页的含义和URL基本构成这系列的文章。我这里主要介绍的是python3.3.2的urllib2的实现。

  

  首先,下面是一个简单的抓取网页信息程序,主要是介绍下urllib的使用。

 

# 简单的抓取HOJ主页的数据
import urllib.request

response = urllib.request.urlopen(\'http://acm.hit.edu.cn\')
html = response.read()
print(html)

# 注意,由于网页抓取下来的是bytes格式的数据,所以写入文件时需要以二进制的方式写入
fout = open(\'txt.txt\',\'wb\')
fout.write(html)
fout.close()

fout = open(\'html.html\',\'wb\') # 写入到文件html.html
fout.write(html)
fout.close()

 

  运行结果应该是txt.txt,html.html两个文件。我们可以打开看看txt.txt、html.html看看,发现txt.txt的数据跟浏览器查看的网页源代码一致。如果用浏览器打开html.html,会发现这个跟我们实际上考看到的网页基本一样。

  


  

模拟HOJ登陆并抓取已经AC的代码

  

  我们需要进行登陆,需要设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie。

    # 设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie
    cj = http.cookiejar.LWPCookieJar()  
    cookie_support = urllib.request.HTTPCookieProcessor(cj)  
    opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)  
    urllib.request.install_opener(opener)  

  

  登陆时需要对HOJ服务器发送数据请求,对于发送data表单数据,我们怎么查看需要发送的数据在HTTP中,这个经常使用熟知的POST请求发送。

  我们可以先查看网页源代码,看到

  

  看到三个name,所以发送的求情数据中需要包含这三个,

    # 构造Post数据,从抓大的包里分析得出的或者通过查看网页源代码可以得到  
    data = {
            \'user\' : user, # 你的用户名
            \'password\' : password, # 你的密码,密码可能是明文传输也可能是密文,如果是密文需要调用相应的加密算法加密
            \'submit\' : \'Login\'  # 特有数据,不同网站可能不同
    }

  

  另外,一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。所以我们需要对data进行编码。

data = urllib.parse.urlencode(data).encode(\'utf-8\')

  

  发送请求,得到服务器给我们的响应,完成登录功能。header最好加上,不然由于内部信息默认显示为机器代理,可能被服务器403 Forbidden拒绝访问。

 

    # 发送请求,得到服务器给我们的响应
    response = urllib.request.Request(url, data,header)
    # 通过urllib提供的request方法来向指定Url发送我们构造的数据,并完成登录过程
    urllib.request.urlopen(response)

  

  登录函数如下:

def login(): # 登陆函数
    print(\'请输入你的账号\')
    user = input()
    print(\'请输入你的密码\')
    password = input()
    
    # 设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie
    cj = http.cookiejar.LWPCookieJar()  
    cookie_support = urllib.request.HTTPCookieProcessor(cj)  
    opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)  
    urllib.request.install_opener(opener)  
    
    url = \'http://acm.hit.edu.cn/hoj/system/login\' # 登陆的界面
    
    # 这个最好加上,不然由于内部信息默认显示为机器代理,可能被服务器403 Forbidden拒绝访问
    header={\'User-Agent\':\'Magic Browser\'}
    
    # 构造Post数据,从抓大的包里分析得出的或者通过查看网页源代码可以得到  
    data = {
            \'user\' : user, # 你的用户名
            \'password\' : password, # 你的密码,密码可能是明文传输也可能是密文,如果是密文需要调用相应的加密算法加密
            \'submit\' : \'Login\'  # 特有数据,不同网站可能不同
    }
    
    data = urllib.parse.urlencode(data).encode(\'utf-8\')
    
    # 发送请求,得到服务器给我们的响应
    response = urllib.request.Request(url, data,header)
    # 通过urllib提供的request方法来向指定Url发送我们构造的数据,并完成登录过程
    urllib.request.urlopen(response)
    
    return

  

 

  登录进去后,我们需要对已经AC的代码进行抓取。抓取的链接为:

  http://acm.hit.edu.cn/hoj/problem/solution/?problem=题目编号

    url = \'http://acm.hit.edu.cn/hoj/problem/solution/?problem=\'+str(i)
    response = urllib.request.urlopen(url)
    html = response.read()

  我们可以把html输出看看具体内容是什么。  

 

  通过查看网页代码,发现提交的代码都是在<span></span>标签中。

  

  因此我们可以对这部分数据进行处理,处理过程中我们可以用到python的正则表达式进行搜索。并且对于特殊的编码如&lt;需要进行解码。

  当然,我们需要注意保存的文件到底是java还是c++。

 

  最后,详细的代码如下:

  

import urllib
import http.cookiejar
#import time

hashTable = { # 网页特殊编码转化
        \'<\':\'<\',
        \'>\': \'>\',
        \'{\':\'{\',
        \'}\':\'}\',
        \'(\':\'(\',
        \')\':\')\',
        \' \':\' \',
        \'&\':\'&\',
        \'[\':\'[\',
        \']\':\']\',
        \'"\':\'"\'
        }

def login(): # 登陆函数
    print(\'请输入你的账号\')
    user = input()
    print(\'请输入你的密码\')
    password = input()
    
    # 设置一个cookie处理器,它负责从服务器下载cookie到本地,并且在发送请求时带上本地的cookie
    cj = http.cookiejar.LWPCookieJar()  
    cookie_support = urllib.request.HTTPCookieProcessor(cj)  
    opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)  
    urllib.request.install_opener(opener)  
    
    url = \'http://acm.hit.edu.cn/hoj/system/login\' # 登陆的界面
    
    # 这个最好加上,不然由于内部信息默认显示为机器代理,可能被服务器403 Forbidden拒绝访问
    header={\'User-Agent\':\'Magic Browser\'}
    
    # 构造Post数据,从抓大的包里分析得出的或者通过查看网页源代码可以得到  
    data = {
            \'user\' : user, # 你的用户名
            \'password\' : password, # 你的密码,密码可能是明文传输也可能是密文,如果是密文需要调用相应的加密算法加密
            \'submit\' : \'Login\'  # 特有数据,不同网站可能不同
    }
    
    data = urllib.parse.urlencode(data).encode(\'utf-8\')
    
    # 发送请求,得到服务器给我们的响应
    response = urllib.request.Request(url, data,header)
    # 通过urllib提供的request方法来向指定Url发送我们构造的数据,并完成登录过程
    urllib.request.urlopen(response)
    
    return


def solve(html,i):
    txt = html.decode(\'gbk\',\'ignore\')
    
    start = txt.find(\'<span\')
    if start==-1: # 没有span,表示此题没AC
        return
    p = \'.java\'
    if txt.find(\'import\')==-1:
        p = \'.cpp\'
        
    fout = open(\'txt_\'+str(i)+p,\'w\')
    while True:
        end = txt.find(\'<span\',start+5)
        if end==-1:
            end = txt.find(\'</span>\',start)
        
        x = txt.find(\'>\',start)+1
        w = \'\'
        
        ok = True
        while x<end:
            if txt[x]==\'<\':
                ok = False
            elif txt[x]==\'>\':
                ok = True
            if not ok or txt[x]==\'>\':
                x += 1
                continue
            
            if txt[x]==\'&\': # 进行特殊的解码
                t4 = txt[x:x+4]
                t5 = txt[x:x+5]
                t6 = txt[x:x+6]
                if t4 in hashTable:
                    w += hashTable[t4]
                    x += 4
                elif t5 in hashTable:
                    w += hashTable[t5]
                    x += 5
                elif t6 in hashTable:
                    w += hashTable[t6]
                    x += 6
                else:
                    w += txt[x]
                    x += 1
            else:
                w += txt[x]
                x += 1
        fout.write(w)
        if end==start:
           break
        start = end
        
    fout.close()
    return


def run(): # 抓取所有AC代码
    for i in range(1001,3169):
        url = \'http://acm.hit.edu.cn/hoj/problem/solution/?problem=\'+str(i)
        response = urllib.request.urlopen(url)
        html = response.read()
        solve(html,i)
        #time.sleep(0.5) # 时间间隔为0.5s发送一次抓取请求,减轻hoj服务器压力
    return


login()
run()

  

我所有的HOJ AC代码,在http://pan.baidu.com/s/1gdsX9DL

  

 


 

 

提交AC代码:

  这个其实跟登陆并抓取AC代码原理基本一样。

  

    # 构造Post数据,从网页数据分析得出
    data = {
            \'Proid\' : num,
            \'Language\' : language,
            \'Source\' : txt # 可以通过查看网页源代码看出
    }

 

  另外,我们需要用到listdir()函数,以此来获得当前目录下所有的文件。

  这里我们需要设置time.sleep(3) ,间隔三秒递交一次代码,减轻服务器压力,以免使得HOJ服务器崩了。

 

  总的代码如下:

import urllib
import http.cookiejar
import time
from os import listdir


def login():
    print(\'请输入你的账号\')
    user = input()
    print(\'请输入你的密码\')
    password = input()
    
    cj = http.cookiejar.LWPCookieJar()  
    cookie_support = urllib.request.HTTPCookieProcessor(cj)  
    opener = urllib.request.build_opener(cookie_support, urllib.request.HTTPHandler)  
    urllib.request.install_opener(opener)  
    
    url = \'http://acm.hit.edu.cn/hoj/system/login\'
    
    header = {\'User-Agent\' : \'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1\',  
           \'Referer\' : \'******\'}
    
    # 构造Post数据,他也是从抓大的包里分析得出的。  
    data = {\'op\' : \'dmlogin\',  
            \'f\' : \'st\', 
            \'user\' : user, # 用户名  
            \'password\' : password, # 密码,密码可能是明文传输也可能是密文,如果是密文需要调用相应的加密算法加密  
            \'submit\' : \'Login\'  # 特有数据,不同网站可能不同  
    }
    
    data = urllib.parse.urlencode(data).encode(\'utf-8\')
    request = urllib.request.Request(url, data,header)
    
    # 通过urllib2提供的request方法来向指定Url发送我们构造的数据,并完成登录过程
    urllib.request.urlopen(request)
    
    return


def solve(file): # file:为文件名,格式是 txt_problemNumber.cpp或者 txt_problemNumber.java
    ed = file.find(\'.\')
    language = file[ed+1:len(file)]
    if language!=\'cpp\' and language!=\'java\':
        return
    if language==\'cpp\':
        language = \'C++\'
    else:
        language = \'Java\'
    st = file.find(\'_\')
    num = file[st+1:ed]
    
    url = \'http://acm.hit.edu.cn/hoj/problem/submit/?id=\'+num
    
    header = {\'User-Agent\' : \'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1\',  
           \'Referer\' : \'******\'}
    
    fin = open(file,\'rb\')
    txt = fin.read().decode(\'gbk\',\'ignore\')
    fin.close()
    
    # 构造Post数据,从网页数据分析得出
    data = {
            \'Proid\' : num,
            \'Language\' : language,
            \'Source\' : txt # 可以通过查看网页源代码看出
    }
    
    data = urllib.parse.urlencode(data).encode(\'utf-8\') # 使用UTF-8编码方式进行编码
    request = urllib.request.Request(url, data,header) # 添加消息头
    
    
    # 通过urllib2提供的request方法来向指定Url发送我们构造的数据,并完成登录过程
    urllib.request.urlopen(request)
    
    time.sleep(3) # 间隔三秒递交一次代码,减轻服务器压力
    
    return


def run():
    allFile = listdir() # 获得当前目录下所有的文件
    for file in allFile:
        solve(file)
    
    return


login()
run()

  

 

codeforces爬AC代码(有些网页格式不太一样,最后直接把那些题目忽略了,囧)(CF python代码尚未正确,有待改进。。。)

import urllib

user = \'yejinru\' # 用户
page = 21        # 提交的页数


def solve(html,name):
    txt = html.decode(\'utf-8\',\'ignore\')
    
    cpp = \'.cpp\'
    start = txt.find(\'include\')-1
    if start==-2:
        start = txt.find(\'public static void Main\')
        if start==-1:
            cpp = \'.py\'
        else:
            cpp = \'.java\'
    
    end = txt.find(\'</pre>\',start+100)
    
    fout = open(\'cf/\'+name+cpp,\'wb\')
    pro = txt[start:end]
    
    pro = pro.replace(u\'<\',u\'<\')
    pro = pro.replace(u\'>\',u\'>\')
    pro = pro.replace(u\'"\',u\'"\')
    pro = pro.replace(u\'&\',u\'&\')
    
    fout.write(pro.encode(\'gbk\',\'ignore\'))
    fout.close()
    return


def fun(html):
    txt = html.decode(\'utf-8\',\'ignore\')
    pre = 0
    while True:
        cur = txt.find(\'<span class=\\'verdict-accepted\\'>\',pre)
        if cur==-1:
            return
        pre = cur+100
        
        p = txt.find( \'"\',txt.find(\'submissionId="\',cur-50) )+1
        pid = \'\'
        while txt[p]!=\'"\':
            pid += txt[p]
            p += 1

        p = txt.find(\'data-problemId="\',cur-300)
        if p==-1:
            return
        p = txt.find(\'>\',txt.find(\'<a href="/\',p))+19
        if p==18:
            return
        tid = \'\'
        
        while txt[p]>=\'0\' and txt[p]<=\'9\':
            tid += txt[p]
            p += 1
        if len(tid)>3:
            continue
        
        url = \'http://codeforces.com/contest/\'+tid+\'/submission/\'+pid
        print(url)
        response = urllib.request.urlopen(url)
        html = response.read()
        
        solve(html,tid+txt[p])
        
        fout = open(\'cf/\'+pid+\'.html\',\'wb\')
        fout.write(html)
        fout.close()
        
    return

def run():
    add = \'/page/\'
    first = \'http://codeforces.com/submissions/\'+user
    
    for i in range(1,page+1): # 这是因为http://codeforces.com/submissions/yejinru这里只有21页
        url = \'\'
        if i==1:
            url = first
        else:
            url = first+add+str(i)
        response = urllib.request.urlopen(url)
        html = response.read()
        fun(html)
        
    return


run()

  

 

分类:

技术点:

相关文章:

  • 2021-11-13
  • 2021-12-18
  • 2021-12-09
  • 2021-04-12
  • 2021-09-05
  • 2018-07-05
  • 2021-11-26
猜你喜欢
  • 2021-11-15
  • 2021-08-22
  • 2021-11-29
  • 2021-06-08
  • 2021-12-28
  • 2020-04-20
  • 2021-04-11
相关资源
相似解决方案