马思边草拳毛动,雕眄青云睡眼开。——刘禹锡《始闻秋风》 楠少博客 阅读文章 Python 爬取蓝桥官网所有试题 楠少 2019-02-16 6666666 8888888 Python 爬虫 蓝桥 摘要 因VIP不久后到期,官网的很多练习题(VIP试题)都没打开过,遂爬之。 进入开发者工具,检查是否有接口,未找到,打开页面源码可以看到,题目的内容已经出现,所以这些题目不是从接口中获取,由此:我们需要解析 DOM 结构。 **目录 (Table of Contents)** [TOC] ### 起因 : 因VIP不久后到期,官网的很多练习题(VIP试题)都没打开过,遂爬之。 ![](https://ae01.alicdn.com/kf/H5a40226b7df8486cb89c0046284af5242.png) ![](https://ae01.alicdn.com/kf/Hf518cc82b0de46aaa96637fa8c8c951fO.png) ### 经过 : #### 过程分析: 进入开发者工具,检查是否有接口,未找到,打开页面源码可以看到,题目的内容已经出现,所以这些题目不是从接口中获取,由此:我们需要解析 DOM 结构。 ![](https://ae01.alicdn.com/kf/H55fc1c3f1f3c4c36bd1fa617b56cc85dv.png) 首先登陆蓝桥练习官网,从 Headers 中将cookie 和 user-Agent 复制下来。 ![](https://ae01.alicdn.com/kf/H900ba4027dbb45a48ff6b7e2998c3083w.png) 以下是各个题目的页面链接 ,不同之处只是参数`gpid`,经粗略查看,范围为 1~519(后 实施过程中发现有部分序号没有题目)。 `http://lx.lanqiao.cn/problem.page?gpid=T210` ### 程序开始: 该过程需导入: ```python import requests # 网络请求 import pymysql # 数据库操作 from lxml import etree # 网页 DOM 解析 ``` 首先创建一个类,在init方法中存下 headers、url、数据库连接字符串和游标。 ```python def __init__(self): self.headers = { "Cookie": "_SESSIONKEY 。。。省略 。。。0307063596", "User-Agent": "Mozilla/。。。省略 。。。77 Safari/537.36" } self.url = "http://lx.lanqiao.cn/problem.page?gpid=T{}" self.conn = pymysql.connect(host="127.0.0.1", user="root", password="123456", database="lanqiao", charset="utf8") self.cursor = self.conn.cursor() ``` 其次创建run函数 实现整体思路: ```python def run(self): urls = self.get_urls() # 获取所有题目的url for i in range(1, len(urls) + 1): # 由于题目需要为 1-519 所以存在 +1 的问题 html = self.get_html_by_url(urls[i-1]) # 从指定url获取页面的HTML代码 data = self.get_data_by_html(html, i) # 从HTML代码中解析DOM元素以获取需要的数据 self.save_data_to_db(data) # 存到数据库 # self.save_data(data) self.save_data_to_file(data) # 存文件 self.close_db() # 关闭数据库 ``` 获取所有url: ```python def get_urls(self): urls = [self.url.format(i) for i in range(1, 520)] return urls 从网页获取源码: def get_html_by_url(self, url): """获取网页源码""" resp = requests.get(url, headers=self.headers) return resp.content.decode() 下载图片: def get_img(self, url, name): """下载图片""" resp = requests.get(url, headers=self.headers) with open("./topics/" + name + ".png", "wb") as f: f.write(resp.content) f.close() 从源码获取题目数据,如有图片,先行保存。 def get_data_by_html(self, html, index): """从源码中获取数据""" eme = etree.HTML(html) data = {} data["tid"] = index data["title"] = eme.xpath("/html/body/div[3]/div[4]/div[1]//text()")[0].strip() data["limit"] = eme.xpath('//*[@id="prbinfos"]/div[1]//text()')[0].strip() context = eme.xpath('//div[@class="des"]//text()') temp = "" for i in context: if len(i.strip()) > 0: temp += i data["context"] = temp img_list = [] try: imgs = eme.xpath('//div[@class="des"]//img/@src') for i in range(0, len(imgs)): img_url = "http://lx.lanqiao.cn" + imgs[i] img_list.append(img_url) self.get_img(img_url, data["title"] + "_" + str(i)) except: pass data["image_list"] = img_list return data 将题目数据保存到数据库,这里用的 mysql 表结构文末附上。 def save_data_to_db(self, data): """保存到数据库""" cursor = self.cursor try: # lx.tid,lx.title,lx.`limit`,lx.context,lx.image_list sql = "INSERT INTO `lx` VALUES (%s, %s, %s, %s, %s)" cursor.execute(sql, [data["tid"], data["title"], data["limit"], data["context"], "".join(data["image_list"])]) except Exception as e: print(e) 将题目数据保存成文本文档。 def save_data_to_file(self, data): """保存到文件""" try: with open("./topics/" + data["title"] + ".txt", "w", encoding="utf-8") as f: f.write(str(data["tid"]) + "\t" + data["title"] + "\n" + data["limit"] + "\n" +data["context"]) f.close() except Exception as e: print(e) 关闭数据库。 def close_db(self): self.cursor.close() self.conn.close() ``` 附上数据库结构: ```sql /* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50721 Source Host : 127.0.0.1:3306 Source Database : lanqiao Target Server Type : MYSQL Target Server Version : 50721 File Encoding : 65001 Date: 2019-02-16 15:56:28 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for lx -- ---------------------------- DROP TABLE IF EXISTS `lx`; CREATE TABLE `lx` ( `tid` int(11) NOT NULL, `title` varchar(255) DEFAULT NULL, `limit` varchar(255) DEFAULT NULL, `context` text, `image_list` text, PRIMARY KEY (`tid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; ``` ### 总结: #### 所用到知识: 1. 浏览器请求数据抓包于分析 2. python 网络请求 3. xpath Dom定位 4. python 数据库操作 5. python 文件 IO 6. SQL 数据库存储 #### 拓展: `python`可视化工具很多,大家可以根据需求,将获取的数据用以可视化展示,可导入第三方库实现图片的生成,也可使用`Flask`框架搭建Web页面,结合百度开源可视化工具 `ECharts`,效果会更好! 官网:https://echarts.baidu.com/ ### END 上一篇:楠少博客 重构计划 下一篇:破解天翼校园WiFi 文章评论 [ 聊聊技术 聊聊自己 ] 在巴甫洛夫条件反射 试验中:给定一条狗,每次摇铃后喂食,足够次数后,狗则听到铃声将会习惯性的分泌唾液,由此引发对铃声的依恋。延伸到实际,给定一个喜欢的妹子,每次见面赠与巴甫洛夫式 的礼品或者零食,由此引发妹子的依恋。引入薛定谔的猫 理论,在未表白前,妹子与自己一直处于一种“概率云”的状态,一旦表白则“概率云”将消失成为实际。在 巴甫洛夫式 后且未表白前,自己与妹子的关系为“既是恋人又不是恋人”的矛盾体。返回巴甫洛夫式 试验中,在妹纸形成足够的依恋过后,则可以打破薛定谔 “概率云”的状态。这个谜一样的自己,这一刻 薛定谔 附体,带着量子论般深沉的哀愁,让她从此不能自拔! 自此创作 巴甫洛夫薛定谔把妹法,深藏功与名。