使用多进程的方式可以提高爬取数的效率。
在Python中,multiprocessing模块可是实现多进程。
该模块实现多进程有几种方式,例如Process多进程类和Pool进程池等。
本次使用Pool进程池的方式来实现多进程的工能。
主要流程如下:
创建进程池
首先实例化Pool()类,然后调用pool实例对象的map方法,这里需要传递2个参数,第一个参数main是进程要执行的函数,第二个参数index是当前页码索引。代码如下:
01 pool = Pool() # 开启进程
02 index = ([x for x in range(totlePageCount)]) # 生成当前页码元组
03 pool.map(main, index) # 执行多进程
04 pool.close() # 关闭进程
05 pool.join() # 等待子进程结束
创建进程执行函数
pool.map()方法中定义了一个要执行的方法参数main,接下来是需要定义main()函数。代码如下:
06 def main(index):
07 # 获取JSON格式数据
08 content_json = get_json(index)
09 # 获取课程内容
10 content = get_content(content_json)
11 # 保存到数据库
12 save_mysql(content)
实例代码
import requests
import time
import pymysql
from multiprocessing import Pool
#连接数据库
conn = pymysql.connect(host='localhost',
port=3306,
user='root',
passwd='root',
db='spider',
charset='utf8')
cur = conn.cursor()
def get_json(index):
"""
爬取课程的Json数据
:param index: 当前索引,从0开始
:return: Json数据
"""
url = "https://study.163.com/p/search/studycourse.json"
payload = {
"activityId": 0,
"keyword": "python",
"orderType": 5,
"pageIndex": index,
"pageSize": 50,
"priceType": -1,
"qualityType": 0,
"relativeOffset": 0,
"searchTimeType": -1,
}
headers = {
"accept": "application/json",
"host": "study.163.com",
"content-type": "application/json",
"origin": "https://study.163.com",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
}
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 course_id: 课程id
:return: 课程存在返回True,否则返回False
"""
# 根据course_id查找course表中记录
sql = f'select course_id from course where course_id = {course_id}'
# 执行SQL语句
cur.execute(sql)
# 查找一条记录
course = cur.fetchone()
# 如果数据库中存在,返回True;否则,返回False。
if course:
return True
else:
return False
def save_to_course(course_data):
"""
保存到course表
:param course_data: 元组数据
:return: None
"""
sql_course = """insert into course
values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
"""
# exetemany方法插入多条记录
cur.executemany(sql_course, course_data)
def save_mysql(content):
"""
保存到MySQL
:param content: 爬取的数据
:return:
"""
course_data = []
# 遍历课程列表
for item in content:
# 如果数据表中没有该条记录,则保留
if not check_course_exit(item['courseId']):
# 加入元组
course_value = (item['courseId'],item['productName'],item['provider'],item['score'],item['learnerCount'],
item['lessonCount'],item['lectorName'],item['originalPrice'], item['discountPrice'],
item['discountRate'],item['imgUrl'], item['bigImgUrl'],
item['description'],)
course_data.append(course_value)
# 调用save_to_course方法,写入数据库
save_to_course(course_data)
def main(index):
# 获取JSON格式数据
content_json = get_json(index)
# 获取课程内容
content = get_content(content_json)
# 保存到数据库
save_mysql(content)
if __name__ == '__main__':
print('开始执行')
start = time.time() # 记录开始时间
# 获取总页数
totlePageCount = get_json(1)['result']["query"]["totlePageCount"]
# 不使用多进程
# for index in range(totlePageCount):
# main(index)
# 使用多进程
pool = Pool() # 开启进程
index = ([x for x in range(1,totlePageCount+1)]) # 生成当前页码元组
pool.map(main, index) # 执行多进程
pool.close() # 关闭进程
pool.join() # 等待子进程结束
cur.close() # 关闭游标
conn.commit() # 提交到数据库
conn.close() # 关闭数据库连接
print('执行结束')
end = time.time() # 记录技术时间
print(f'程序执行时间是{end-start}秒。') # 输出执行时间