本文主要是介绍决战高考,帮你秒变成语之王,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
又是一年高考季
每年的这时候我都要发一条朋友圈,要高考了好紧张,哈哈...
没开始做公众号时,在公司内网隔三差五发篇博文,感觉自己思维好活跃。可从上周五写第一篇公众号开始,说巧不巧的工作开始忙起来了。每天赶着最后一班车回家,吃完饭和孩子玩一会就快10点了。然后坐在电脑旁边稳定半天的情绪开始学习,等学的差不多开始搞公众号。这一周1天通宵5天3点后,感觉身体被掏空。但希望能坚持每天发一篇真的能给大家带来帮助的文章,那么今天发什么?如题...
成语之王
想想今天高考,第一门就是语文,所以考虑发一篇和语文有关的内容。
回忆我们那会儿考语文,第一道题肯定和成语、拼音的判断对错和修改有关。那就发这个吧!
百度了一下,找到一个haoshiwen.org的网站,对应的有一个chengyu.haoshiwen.org子域名。其中包含了很多的成语,点到每个成语中,又包含了成语、注音、释义、出处、示例、成语热度,很是不错。
网站分析
坦白说,这个网站真的比较简单,就是PHP(世界上最好的语言...)搭建的静态网站。
网站将成语通拼音首字母从A-Z进行了划分,然后每个字母一页一页的记录,网址模式如下:
http://chengyu.haoshiwen.org/list.php?t=A&page=2
每个成语的链接点进去就是成语详情,url类似如下:
http://chengyu.haoshiwen.org/view.php?id=40
这样解析起来就很简单了...
- 我们首先创建双重for循环,character从A到Z、page 1--100,然后开始爬取网站
- 通过正则匹配所有href属性带有/view.php?id=数字的a标签进行网站拼接后的二次访问
- 进入访问页面,获取第一个table中的成语名、注音、释义、出处、示例、成语热度
- 成语热度的排名,进行字符串的切割后,转为int,已做成语热度排序
- 最终将数据进行存储
... 部分代码 ...def traverse_character(self):# page style: http://chengyu.haoshiwen.org/list.php?t=A&page=1url = self.url + '/list.php'for char in ascii_uppercase:for page_num in range(1, 100):params = {"t": char, "page": page_num}soup = self.get_response(url, params)links = soup.findAll("a", {"href": re.compile("/view.php\?id=\d")})if not links:continuefor link in links:t = threading.Thread(target=self.idiom_index, args=(self.url + link["href"],))t.start()time.sleep(0.1)def idiom_index(self, url):sem.acquire()try:soup = self.get_response(url)tr = soup.find("table").findAll("tr")[:6]info = {td.findAll('td')[0].text: td.findAll('td')[1].text for td in tr}info['人气'] = int(info['人气'][:-1])sql = "insert into idiom (name,speak,meaning,source,example,hot) values " \"(?,?,?,?,?,?)"self.db.insert(sql,list(info.values()))except Exception as error_info:print(error_info)finally:sem.release()... 部分代码 ...
怎么存?
其实这种数据,用postgresql和mongodb亦或者是大众常用的Mysql来搞是比较好的。但其实这里有一个小打算,就是把数据全部拿到之后做一个其他的功能,为了能轻松复制,我选择了相对性能弱但是便携的SQLite。
那选择了数据库,用什么来管理数据库链接呢? DBUtils
安装:pip install DBUtils
介绍:
DBUtils is a suite of tools providing solid, persistent and pooled connections to a database that can be used in all kinds of multi-threaded environments like Webware for Python or other web application servers. The suite supports DB-API 2 compliant database interfaces and the classic PyGreSQL interface.
简而言之,DBUtils是一套为数据库提供可靠,持久和池式连接的工具,可用于各种多线程环境。我们一般使用DBUtils.PooledDB来创建一批连接池进行并发处理。常用参数如下:
参数 | 说明 |
---|---|
creator | 使用链接数据库的模块(sqllite3、pymysql...) |
maxconnections | 连接池允许的最大连接数,0和None表示不限制连接数 |
mincached | 初始化时,链接池中至少创建的空闲的链接,0表示不创建 |
maxcached | 链接池中最多闲置的链接,0和None不限制 |
blocking | 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 |
maxusage | 一个链接最多被重复使用的次数,None表示无限制 |
host | ip |
user | 用户名 |
password | 密码 |
database | 数据库名 |
charset | 字符集(Mysql用的比较多,SQLite没有) |
因为之前都是拿DBUtils链接数据库的,这次默认就直接改成sqlite3,结果各种报错(SQLite数据库没有host、user、password、charset的选项)。
然后好不容易配置好了,封装上常用的方法...一跑程序挂了!
SQLite本身应对多个线程并发访问过程中的冲突问题,由一个线程创建并访问的sqlite的数据库,无法允许另外一个线程进行访问,找解决办法呗,最终找到通过设置check_same_thread=False,使SQLite支持多线程并发(但并发的效果很一般)。
# -*- coding: utf-8 -*-
# @Author : 王翔
# @JianShu : 清风Python
# @Date : 2019/6/7 02:23
# @Software : PyCharm
# @version :Python 3.6.8
# @File : db_maker.pyimport sqlite3
from DBUtils.PooledDB import PooledDBclass DB_Maker:def __init__(self):self.POOL = PooledDB(check_same_thread=False,creator=sqlite3, # 使用链接数据库的模块maxconnections=10, mincached=2, maxcached=5, blocking=True, maxusage=None, ping=0,database='database.db',)self.check_db()def check_db(self):sql = "SELECT name FROM sqlite_master where name=?"if not self.fetch_one(sql, ('idiom',)):self.create_table()def create_table(self):print("create table ...")sql = """create table idiom ([id] integer PRIMARY KEY autoincrement,[name] varchar (10),[speak] varchar (30),[meaning] varchar (100),[source] varchar (100),[example] varchar (100),[hot] int(10))"""self.fetch_one(sql)def db_conn(self):conn = self.POOL.connection()cursor = conn.cursor()return conn, cursor@staticmethoddef db_close(conn, cursor):cursor.close()conn.close()def fetch_one(self, sql, args=None):conn, cursor = self.db_connif not args:cursor.execute(sql)else:cursor.execute(sql, args)record = cursor.fetchone()self.db_close(conn, cursor)return recorddef fetch_all(self, sql, args):conn, cursor = self.db_conncursor.execute(sql, args)record_list = cursor.fetchall()self.db_close(conn, cursor)return record_listdef insert(self, sql, args):conn, cursor = self.db_connrow = cursor.execute(sql, args)conn.commit()self.db_close(conn, cursor)
程序引入threading多进程的方式,并发网页请求。主程序代码如下:
# -*- coding: utf-8 -*-
# @Author : 王翔
# @JianShu : 清风Python
# @Date : 2019/6/7 02:52
# @Software : PyCharm
# @version :Python 3.6.8
# @File : IdiomCrawler.pyimport requests
from bs4 import BeautifulSoup
import re
import threading
import time
from string import ascii_uppercase
from db_maker import DB_Makerclass IdiomCrawler:def __init__(self):self.url = "http://chengyu.haoshiwen.org"self.headers = {'Host': "chengyu.haoshiwen.org",'Connection': 'keep-alive','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8','user-agent': ('Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ''(KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36')}self.db=DB_Maker()def get_response(self, url, params=None):r = requests.get(url, headers=self.headers, params=params)r.encoding = 'utf-8'soup = BeautifulSoup(r.text, "lxml")return soupdef traverse_character(self):# page style: http://chengyu.haoshiwen.org/list.php?t=A&page=1url = self.url + '/list.php'for char in ascii_uppercase:for page_num in range(1, 100):params = {"t": char, "page": page_num}soup = self.get_response(url, params)links = soup.findAll("a", {"href": re.compile("/view.php\?id=\d")})if not links:continuefor link in links:t = threading.Thread(target=self.idiom_index, args=(self.url + link["href"],))t.start()time.sleep(0.1)def idiom_index(self, url):sem.acquire()try:soup = self.get_response(url)tr = soup.find("table").findAll("tr")[:6]info = {td.findAll('td')[0].text: td.findAll('td')[1].text for td in tr}info['人气'] = int(info['人气'][:-1])sql = "insert into idiom (name,speak,meaning,source,example,hot) values " \"(?,?,?,?,?,?)"self.db.insert(sql,list(info.values()))except Exception as error_info:print(error_info)finally:sem.release()if __name__ == '__main__':sem = threading.Semaphore(5) # 设置线程阀值Crawler = IdiomCrawler()Crawler.traverse_character()while threading.active_count() != 1:pass # print threading.active_count()else:print('### Selenium Jobs is over!!!###')
不爬不知道一爬吓一跳,中国有这么多的成语,看了几集Flask视频了,才终于搞完。
来看看我们的数据吧....
检查下有没有重复数据,结果ok:
再来看看网站排名的成语热度吧:
这个热度就有点坑了,明显是访问次数么,因为这个 哀哀父母是第一个词,所以热搜最高。最重要的是我不知道这是啥意思,哈哈......
辛辛苦苦把三万个成语爬下来,就这么结束了貌似不太好,抽时间拿这些数据搞点事情。
如果大家想要这份成语数据库,关注我的公众号【清风Python】,回复成语
,即可获取。
好了,今天的内容就到这里,如果觉得有帮助,记得点赞支持。欢迎大家关注我的公众号,获取更多Python相关的知识,并有整理好的各类福利数据供大家下载:
这篇关于决战高考,帮你秒变成语之王的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!