多进程课程数据爬取存放MySql数据库
需求描述:
爬取网易云课堂课程信息,并使用PyMySql模块将数据保存到MySQL数据库中。
核心技术:PyMySQL模块操作数据库,multiprocessing模块可以实现多进程。本例使用Pool进程池的方式来实现多进程的功能
前期准备:
创建数据库
utf-8
CREATE DATABASE pydb DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
创建课程数据表
-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course_pro`;
CREATE TABLE `course_pro` (
`course_id` bigint(20) NOT NULL COMMENT '课程id',
`product_id` bigint(20) NOT NULL COMMENT '产品id',
`product_type` int(11) NOT NULL COMMENT '产品类型',
`product_name` varchar(125) NOT NULL COMMENT '产品名称',
`provider` varchar(125) NOT NULL COMMENT '厂家',
`score` float DEFAULT NULL COMMENT '分数',
`score_level` int(11) DEFAULT NULL COMMENT '分数等级',
`learner_count` int(11) DEFAULT NULL COMMENT '学习者数量',
`lesson_count` int(11) DEFAULT NULL COMMENT '课程数量',
`lector_name` varchar(125) DEFAULT NULL COMMENT '读者名',
`original_price` float DEFAULT NULL,
`discount_price` float DEFAULT NULL COMMENT '折扣价格',
`discount_rate` float DEFAULT NULL COMMENT '折扣比例',
`img_url` varchar(125) DEFAULT NULL COMMENT '图片url地址',
`big_img_url` varchar(255) DEFAULT NULL COMMENT '大图url地址',
`description` text CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT '描述',
PRIMARY KEY (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
安装 pymysql
pip install pymysql -i
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
阿里云 http://mirrors.aliyun.com/pypi/simple/
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
华中理工大学 http://pypi.hustunique.com/
山东理工大学 http://pypi.sdutlinux.org/
豆瓣 http://pypi.douban.com/simple/
python代码实现
import requests
import time
import pymysql
from multiprocessing import Pool
conn = pymysql.connect(
host='192.168.10.102',
port=3306,
user='root',
passwd='mysql123',
db='pydb',
charset='utf8'
) # 连接数据库
cur = conn.cursor()
def get_json(index):
'''
爬取课程的JSON数据
:param index: 当前索引,从0开始
:return: JSON数据
'''
# 此url的获取是登录https://study.163.com/
# 点击网易network
# 点击搜索python查看network中的json
url = 'https://study.163.com/p/search/studycourse.json'
payload = {
'activityId': 0,
'keyword': "python",
'orderType': 50,
# 'pageIndex': 1,
'pageIndex': index + 1,
'pageSize': 50,
'priceType': -1,
'qualityType': 0,
'relativeOffset': 0,
'searchTimeType': -1,
}
headers = {
'authority': 'study.163.com',
'accept': 'application/json',
'accept-encoding': 'gzip, deflate, br',
'content-type': 'application/json',
'origin': 'https://study.163.com',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3868.400 QQBrowser/10.8.4394.400'
}
try:
# 发送POST请求
response = requests.post(url, json=payload, headers=headers)
# 获取JSON数据
content_json = response.json()
if content_json and content_json['code'] == 0:
return content_json
return None
except Exception as e:
print('出错,请核实后重试!')
print(e)
return None
def get_content(content_json):
'''
获取课程信息列表
:param content_json: 获取的JSON格式数据
:return: 课程数据
'''
if 'result' in content_json:
return content_json['result']['list']
def check_course_exit(course_id):
'''
检查课程是否存在:
:param couse_id: 课程ID
:return: 课程存在返回True,否则返回False
'''
print(f'check_course_exit {course_id}')
sql = f'select course_id from course where course_id = {course_id}'
print(f'check_course_exit: {sql}')
cur.execute(sql)
course = cur.fetchone()
if course:
return True
else:
return False
def save_to_course(course_data):
# sql_course = '''insert into course(`course_id`,`product_id`,`product_type`,`product_name`,`provider`,`score` ,`learner_count`,`lesson_count` ,`lector_name` ,`original_price` ,`discount_price`,`discount_rate`,`img_url`,`big_img_url`,`description`) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) '''
sql_course = '''insert into course values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) '''
print('save_to_course')
print(sql_course)
print(course_data)
#executemany插入多条记录
cur.executemany(sql_course, course_data)
def save_mysql(content):
course_data = []
# Column count doesn't match value count at row 1
# 列不匹配
try:
for item in content:
print(item)
#如果数据库没有该条数据则保留
if not check_course_exit(item['courseId']):
#加入元组中
course_value = \
(item['courseId'], item['productId'], item['productType'], item['productName'],
item['provider'], item['score'], item['scoreLevel'], item['learnerCount'],
item['lessonCount'], item['lectorName'], item['originalPrice'], item['discountPrice'],
item['discountRate'], item['imgUrl'], item['bigImgUrl'], item['description']
)
print('course_value:', course_value)
course_data.append(course_value)
save_to_course(course_data)
except Exception as ex:
print('save_mysql', ex)
def main(index):
#获取JSON格式数据
content_json = get_json(index)
#获取课程内容
content = get_content(content_json)
#保存到数据库
save_mysql(content)
conn.commit() # 提交到数据库
if __name__ == '__main__':
print('开始执行')
start = time.time()
#获取总页数
totlePageCount = get_json(1)['result']['query']['totlePageCount'] # 获取总页数
print('totlePageCount', totlePageCount)
# if totlePageCount > 0:
# for i in range(totlePageCount):
# main(i + 1)
#使用多进程
pool = Pool()
#生成当前页码元组
index = ([x for x in range(totlePageCount)])
#执行多进程
pool.map(main,index) #执行多进程
pool.close() #关闭进程
pool.join()#等待子进程结束
cur.close() #关闭游标
#conn.commit() # 提交到数据库
conn.close() # 关闭数据库连接
print('执行结束')
end = time.time()
print(f'程序执行时间是{end - start}秒.')
# 程序执行时间是3.5287063121795654秒.
# 耗时3.5秒中