linux查看oj系统l数据库,用python抓取oj题目(2)——Sqlalchemy将数据存到数据库

上一篇用BS分析好界面元素之后,将我们需要的信息放到一个info的list里面给返回来出来,方便期间,info包括这些东西

##        """ return 12 infos

##        1.title 2.limit des 3.problem des 4.input 5.output

##        6.sample input 7.sample output 8.hint 9.author

##        10.source 11.recommend 12.imgages

##        the last element is a list of images """

info的最后一个元素是一个图片的list。

现在那,有了这些个信息,就需要把他们存到数据库里了。额,想了一下,图片的地址就不存来,直接把图片下来,然后通过html来引用就好了。所以,需要记录info里面的前11条信息,以及1个题号。

先上代码(需要导入的东西忘了粘了from sqlalchemy import *        from sqlalchemy.orm import * ):

1 def store(start, end, url=''):

2     engine = create_engine("mysql://root:duoduo@localhost:3306/test?charset=utf8", encoding="utf-8", echo=True)

3     metadata = MetaData()

4     hdoj_table = Table('hdoj', metadata,

5             Column('problem_id', Integer, primary_key=True),

6             Column('title', String(255), nullable=False),

7             Column('limit_description', String(255), nullable=False),

8             Column('problem_description', Text, nullable=False),

9             Column('input', Text, nullable=False),

10             Column('output', Text, nullable=False),

11             Column('sample_input', Text, nullable=False),

12             Column('sample_output', Text, nullable=False),

13             Column('hint', Text, nullable=True),

14             Column('author', String(40), nullable=True),

15             Column('source', Text, nullable=True),

16             Column('recommend', String(255), nullable=True),

17             )

18

19     class Hdoj(object):

20         def __init__(self, problem_id, title, limit_description, problem_description, input, output, sample_input, sample_output, hint, author, source, recommend):

21             self.problem_id = problem_id

22             self.title = title

23             self.limit_description = limit_description

24             self.problem_description = problem_description

25             self.input = input

26             self.output = output

27             self.sample_input = sample_input

28             self.sample_output = sample_output

29             self.hint = hint

30             self.author = author

31             self.source = source

32             self.recommend = recommend

33

34         def __repr__(self):

35             return "" % (self, title)

36

37     metadata.create_all(engine)

38

39     mapper(Hdoj, hdoj_table)

40

41     Session = sessionmaker(autoflush=True, bind=engine)

42

43     session = Session()

44

45     data = []

46     images = []

47     for i in range(start, end):

48         problem_id = str(i)

49         info = catch(url + problem_id)

50         if info[2] == 'None':

51             continue

52         data.append(Hdoj(problem_id, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[8], info[9], info[10]))

53         images.append(info[-1])

54

55

56     length = len(data)

57     for i in range(length):

58         try:

59             session.add(data[i])

60             session.flush()

61             print 'adding'

62         except Exception as e:

63             #print 'exception'

64             #print e

65             session.rollback()

66             pass

67     return images

解释:

1 def store(start, end, url=''):

start和end是开始到结束的题号,例如我想把1000~2000题都给存下来,那么就store(1000,2000)就好了,url就是之前分析过的默认题目前缀。

2     engine = create_engine("mysql://root:123@localhost:3306/test?charset=utf8", encoding="utf-8", echo=True)

sqlalchemy里面的,sqlalchemy那就像是一个抽象出来的基类一样的东西,你只需要建立一个数据库的引擎,然后就可以在这个数据库上操作,具体的数据库的一些建表插入操作都不用你来操心了,非常方便。例如,我这个引擎是的,用户名为root,密码123,字符集utf8,echo是为了显示一下sqlalchemy到底干了什么,所以设定为True,当然正式发布的时候需要改成False。

1     metadata = MetaData()

2     hdoj_table = Table('hdoj', metadata,

3             Column('problem_id', Integer, primary_key=True),

4             Column('title', String(255), nullable=False),

5             Column('limit_description', String(255), nullable=False),

6             Column('problem_description', Text, nullable=False),

7             Column('input', Text, nullable=False),

8             Column('output', Text, nullable=False),

9             Column('sample_input', Text, nullable=False),

10             Column('sample_output', Text, nullable=False),

11             Column('hint', Text, nullable=True),

12             Column('author', String(40), nullable=True),

13             Column('source', Text, nullable=True),

14             Column('recommend', String(255), nullable=True),

15             )

metadata是神马我不是很了解,(元数据??),总之先记下来用着,然后就是新建一个表,每个oj一张表,所以,就有了上面这2~15行,单词描述的比较明显,不解释了就。

1 class Hdoj(object):

2         def __init__(self, problem_id, title, limit_description, problem_description, input, output, sample_input, sample_output, hint, author, source, recommend):

3             self.problem_id = problem_id

4             self.title = title

5             self.limit_description = limit_description

6             self.problem_description = problem_description

7             self.input = input

8             self.output = output

9             self.sample_input = sample_input

10             self.sample_output = sample_output

11             self.hint = hint

12             self.author = author

13             self.source = source

14             self.recommend = recommend

15

16         def __repr__(self):

17             return "" % (self, title)

18

19     metadata.create_all(engine)

20

21     mapper(Hdoj, hdoj_table)

接下来新建一个Hdoj的类,并且讲这个类与刚刚建的数据表做好映射。

1~14行就是Hdoj了

19、20行里面,是sqlalchemy的东西了,19行是真正的建立引擎,20行是将类与的数据库的表做映射。

接下来是存储:

1     Session = sessionmaker(autoflush=True, bind=engine)

2

3     session = Session()

4

5     data = []

6     images = []

7     for i in range(start, end):

8         problem_id = str(i)

9         info = catch(url + problem_id)

10         if info[2] == 'None':

11             continue

12         data.append(Hdoj(problem_id, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[8], info[9], info[10]))

13         images.append(info[-1])

14

15

16     length = len(data)

17     for i in range(length):

18         try:

19             session.add(data[i])

20             session.flush()

21             print 'adding'

22         except Exception as e:

23             #print 'exception'

24             #print e

25             session.rollback()

26             pass

27     return images

session这个东西,个人的理解就是一次链接,在这儿一个session就是python和数据库的一次链接,然后我们对这个session进行一系列操作,存储啊添加啊神马的,注意,只要session没有flush(),操作都是在缓存里面进行的,查文档发现commit()是提交的一个函数,它里面是会调用flush()的。

1     Session = sessionmaker(autoflush=True, bind=engine)

用sessionmaker建立一个Session,绑定了之前建立的引擎。

3     session = Session()

建立一个Session(你用sessionmaker建立的特殊的一个链接)的对象。

5~13都是添加对象

8         problem_id = str(i)

9         info = catch(url + problem_id)

用之前写好的catch函数抓取需要的信息,存到info里面,注意url变了,这样来进行题目的遍历。

10         if info[2] == 'None':

11             continue

这两行是防止神马的,防止数据库加入没有的题目,比如杭电的题目就到4186,如果store(10000,10010),会把着些没有的url给存到数据库里面,这不是我们想要的,如果没有这个题目的话,让他默默的失败,进行下一个链接。

5     data = []

6     images = []

12         data.append(Hdoj(problem_id, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[8], info[9], info[10]))

13         images.append(info[-1])

data是我真正想存到数据库里面的信息,images则是不想存到里面的图片信息,分开分开。

1     length = len(data)

2     for i in range(length):

3         try:

4             session.add(data[i])

5             session.flush()

6             print 'adding'

7         except Exception as e:

8             #print 'exception'

9             #print e

10             session.rollback()

11             pass

12     return images

这几行是最重要,这是真正把数据放到数据库里的。

首先要说明为什马要用异常,我的主键用的是题号啊,第一次store(1000,1120)的时候一般是不会错的,如果第二次我想store(1100,1200),数据库会告诉我主键重复,不能添加,额,这个当时纠结了好久,各种查,无果,学长告诉我说你可以抓异常啊,弱弱的说一句,我这还真是第一次用异常,没想到介么好用、、

然后是rollback(),rollback像他的名字一样,回滚。session在进行一次链接的时候,每条数据和数据库链接在一起,直到等到rollback它才进行下一条数据的链接(这都是我自己感觉的,如果不对啊话@我下下,学习中),额、怎么说那,举个例子吧,如果说我存store(1055,1070),在1056题,4行添加数据,5行想要更新缓存,写入数据库的时候出现异常了,假设没有rollback这个函数,仅仅是pass的话,session着个叫做链接的东西依然把python和数据库里面的1056进行链接,而不会向下走,结果就是下面的14条数据继续异常,而且给的异常都是第1056题目的主键重复,就是说在循环继续后,数据库并没有断开和1056题的链接,依然尝试把1056题的数据加进来。(这些是真的啊,就不回去实验截图了,一会儿还要上课)

信息要一条一条的存,包不准那一条就会有异常。虽然说session有个addAll()函数,但是如果里面有一条数据出了异常,如果用我第10行的处理机制,那么那一条异常数据后面的所有数据全部都不能添加了。

由于不想把图片存到数据库里面,把它直接return出去了,新写一个函数把图片存到本地。

就是用python处理文件的那一套,代码:

1 def download_img(url, default_url_head='http://acm.hdu.edu.cn/data/images/', default_file_head='/home/duoduo/images/', pro_file_head='hdoj'):

2     filename = url.split('/')[-1]

3     url_head = default_url_head

4     file_head = default_file_head

5

6     url_path = url_head + filename

7     #print url_path

8     file_path = file_head + pro_file_head + '/' + filename

9     #print file_path

10     try:

11         open_img = urllib2.urlopen(url_path)

12         img = open_img.read()

13         img_file = open(file_path, 'wb')

14         img_file.write(img)

15         img_file.close()

16         print 'downloading images from:' + url_path

17     except:

18         print 'HTTP Error 404: Not Found'

19         pass

第2~9行就是把url和本地的路径进行一些处理

10~19行下载,依然要抓异常,因为有些图本身就挂了,打不开,会弹出404异常

13~15就是文件的读写操作,把图片信息存起来来。

存储就到这里了,然后包一下,做一个start函数,把上面的东西都给装进来:

1 def start(begin, end):

2     if(end < begin):

3         print '输入有误,请检查您的输入。'

4         return None

5

6     default_group_num = 50

7     groups = (end - begin) / default_group_num

8

9     for i in range(groups):

10         group_start = i * default_group_num + begin

11         group_end = (i + 1) * default_group_num + begin

12         images_list = store(group_start, group_end)

13         len_img_list = len(images_list)

14         for i in range(len_img_list):

15             len_img = len(images_list[i])

16             for j in range(len_img):

17                 download_img(images_list[i][j])

18

19     if (end - begin) >= 0 :

20         last_group_start = groups * default_group_num + begin

21         images_list = store(last_group_start, end + 1)

22         len_img_list = len(images_list)

23         for i in range(len_img_list):

24             len_img = len(images_list[i])

25             for j in range(len_img):

26                 download_img(images_list[i][j])

6     default_group_num = 50

默认一次存多少数据,我怕一次存太多,内存受不了,或者是等了10来分钟结果中途崩了,还要从头来,麻烦。

7     groups = (end - begin) / default_group_num

groups以及一下的for循环就是做分组处理的。

python抓数据,存数据就彻底ok了,下一步就是用django显示看看是否正确,django的静态文件这次是深刻体会了,上课去先,晚上或者明天在写下一篇吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值