python爬虫抓取LeetCode题目

来源:互联网 发布:编程电脑配置要求2017 编辑:程序博客网 时间:2024/06/05 04:19

最近不知道为什么leetcode有时候会上不去,不能愉快的刷题了。
毛主席教导我们要自己动手,丰衣足食,于是,这几天学习了一下python,写了个简单的爬虫抓取leetcode上的题目。
以前没有接触过python,于是,网上找资料学习基础语法,学了一下变量,循环,选择,函数之类的语法。然后找了一些爬虫的基本知识和ptyhon爬虫的简单例子,花了一天时间写了一个简单的爬虫。

好了,废话不多说,开始进入正题。
为了处理http请求和解析html引入第三库Requests和BeautifulSoup。
这里写图片描述

这是leetcode的题目列表,可以看出题目是放在一个table里面的,再查看源码,找到那个table

<table id="problemList" class="table table-striped table-centered">

所以首先找到id为‘problemList’的table,table有thead和tbody,通过审查元素可以看出来题目信息在tbody的tr标签里

<tr>                  <td style="display: none;">                    <span class="None"> </span>                  </td>                  <td>253</td>                    <td>                      <a href="/problems/meeting-rooms-ii/">Meeting Rooms II</a>                      <i class="fa fa-lock"></i>                    </td>                  <td>29.7%</td>                  <td value="2">Medium</td>                </tr>

这里可以看出来题目信息嵌在各个td里面,所以我们可以通过BeautifulSoup的函数来获得其中信息。

a标签里面有链接,通过链接可以获得具体题目。
题目分为免费和付费,从源码可以看出来两者的差别在于有没有i标签,所以只要找到所有没有i标签的tr就行了。
点开具体题目,查看源代码。
这里写图片描述

可以看出来题目信息在一个class为question-content的div里面
只要获得这个div子元素里面的文字就能抓取到题目信息。
找到规律之后就可以开始编码了。

#coding=utf-8 '''author Jon Leedate 8/9/2015'''import requestsfrom bs4 import BeautifulSoupimport os#获得题目内容def getProblemContent(href):    url = 'https://leetcode.com' + href    try:        req = requests.get(url,headers = headers,timeout=20)    except (requests.exceptions.ReadTimeout,requests.exceptions.ConnectTimeout):#处理连接超时        print('time out')        return 'time out'    problemPage = BeautifulSoup(req.text)    questionContents = problemPage.select('.question-content')#找到存放题目的div    contents = questionContents[0].find_all(['p','pre'])#找到所有p和pre标签    contentText  = ''    for content in contents:        contentText += content.get_text()    req.close()    return contentText#写入文件def saveQuestion(content):    #content['title'].replace(' ','_')#将空格替换成_    name = content['id'] + '_' + content['title'] + '.txt'#文件名 id_title.txt  如 242_Valid Anagram.txt    if not os.path.exists(name):#文件不存在 创建文件        print('create',name)        f = open(name,'wb+')#打开文件  准备写入#这里有个问题 直接写入 content['content']会报编码错误        f.write(content['content'].encode(encoding='utf_8'))#写入文件        f.close()#关闭文件#伪装成浏览器headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'}r = requests.get('https://leetcode.com/problemset/algorithms/',headers = headers)#print(r.status_code)#print(r.text)soup = BeautifulSoup(r.text)#print(soup.title.string)#找到题目所在位置table = soup.find(id='problemList')#题目信息存放在tbody的tr中  找出所有trtr = table.tbody.find_all('tr')#找出其中免费题目  观察源码  没有i标签的即为免费题目problemListEasy = []  #初始化列表  用于存放题目problemListMedium = []  #初始化列表  用于存放题目problemListHard = []  #初始化列表  用于存放题目for problem in tr:    if type(problem.find('i')) is type(None):        #记录题目 id title link acceptance difficulity 以字典方式存入列表        td = problem.find_all('td')        p_id =td[1].string        title = td[2].a.string        link = td[2].a.get('href')        acceptance = td[3].string        difficulity = td[4].string        #读取内容        content = getProblemContent(link)        #print(content)        p_dict = {'id':p_id,'title':title,'content':content,'acceptance':acceptance,'difficulity':difficulity}        print(p_dict['id'])        #将问题根据难度放入不同列表        if difficulity == 'Easy':            problemListEasy.append(p_dict)        elif difficulity == 'Medium':            problemListMedium.append(p_dict)            else:            problemListHard.append(p_dict)#文件操作  创建存放题目的目录及文件#切换路径os.chdir('F:\ComputerRobotData')if not os.path.exists('leetcode'):#目录不存在  则创建    os.mkdir('leetcode')os.chdir('leetcode')#创建easy medium hard三个目录存放相应题目if not os.path.exists('easy'):#目录不存在  则创建    os.mkdir('easy')if not os.path.exists('medium'):#目录不存在  则创建    os.mkdir('medium')if not os.path.exists('hard'):#目录不存在  则创建    os.mkdir('hard')#写入简单题os.chdir('easy')#print(problemListEasy)for pEasy in problemListEasy:    saveQuestion(pEasy)#写入中等题os.chdir('../medium')#print(problemListMedium)for pMedium in problemListMedium:    saveQuestion(pMedium)#写入困难题os.chdir('../hard')#print(problemListHard)for pHard in problemListHard:    saveQuestion(pHard)      print('finish!!') 

这样就能抓取题目并保存到本地了。

遇到问题:

在写入文件的时候直接写入content[‘content’]会报错,UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xa9’ in position 49: illegal multibyte sequence,可是我的编码已经设置成utf-8,所以,无奈之下改用二进制数据写入,问题解决。但是上面那个错误是怎么回事,希望各位大神指导。

刚开始接触python,感觉还是挺有趣的,整个程序也就100多行。不过,虽然效果是可以实现,但是整段代码并没有优化过,基本上是函数式的编程,没有体现封装和面向对象的思想,以后还有很大的优化空间。

0 0
原创粉丝点击