1. 爬取在線課程Excel版
昨天呢筆者外出去吃了一頓火鍋,疫情期間在家饞了好久勒,所以就沒有更新Python的每日一練,今天中午吃了飯之後,趕緊打開電腦給補上,嘿嘿。今天的案例主要是去爬取網易雲課堂上與Python相關的1200多門
課程。如圖所示。
如果我們要在網易雲上發佈一門Python課程,那麼就要對競品進行分析。而要對競品分析,首先要獲取競品數據,那麼使用爬蟲技術再合適不過了。使用Python爬蟲技術爬取網易雲課堂全部Python課程數據,並將爬取到的課程信息數據寫入到Excel表格
中。這個案例的技術要點就是將數據輸入存入Excel
,我們使用xlsxwriter模塊
實現該功能。使用前一定要安裝該模塊:
pip install --user -i http://pypi.douban.com/simple --trusted-host pypi.douban.com xlsxwriter
效果如圖所示:
使用xlsxwriter模塊
基本步驟及流程如下所示:
import xlsxwriter # 1.導入
# 2.創建Excel文件 參數爲: Excel名稱
work_book = xlsxwriter.Workbook("網易雲課堂Python課程數據.xlsx")
# 3.創建sheet
work_sheet = work_book.add_worksheet("Sheet1")
# 4.寫入數據
# 第一個參數表示行(從0開始) 第二個參數表示列(從0開始) 第三個參數是該表格的內容
work_sheet.write(0, 0, "商品ID")
work_sheet.write(0, 1, "課程ID")
work_sheet.write(0, 2, "商品名稱")
work_sheet.write(0, 3, "商品類型")
work_sheet.write(0, 4, "機構名稱")
work_sheet.write(0, 5, "評分")
# 5.關閉excel寫入
work_book.close()
運行程序,使用xlsxwriter模塊
生成的Excel表格如圖所示。
先來分析一下網易雲課堂Python課程頁面。在百度搜索框
中輸入網易雲課堂
訪問網易雲課堂首頁,在首頁搜索欄中輸入Python
關鍵字,進入Python課程
頁面,然後單擊全部
選項,顯示全部Python課程
,如下圖所示。
進入到上面的頁面之後,在網頁上任意一個空白地方單擊鼠標右鍵
,選擇檢查
。調出了控制檯之後,然後點擊Network
,在按F5
或者是瀏覽器左上角
刷新頁面。如圖所示。
我們發現課程信息沒有直接顯示頁面中,而是保存在studycourse.json
文件中,如圖所示。
通過以上分析,下面我們就可以使用requests模塊
來獲取課程數據信息,使用xlsxwriter模塊
將課程信息寫入到Excel表格。具體步驟如下:
1.由於使用了第三方模塊requests
和xlsxwriter
,所以需要先安裝該模塊。已經安裝過的可以不用再安裝。使用pip命令如下:
pip install --user -i http://pypi.douban.com/simple --trusted-host pypi.douban.com requests
pip install --user -i http://pypi.douban.com/simple --trusted-host pypi.douban.com xlsxwriter
2.導入程序中需要使用的模塊,具體代碼如下:
import requests
import xlsxwriter
3.首先使用requests模塊
發送POST
請求, 獲取到當前頁數的課程信息,然後使用json()方法
獲取到Json格式數據
,接下來使用xlsxwriter模塊
將獲取到的當前頁數的信息寫入到Excel。最後在依次遍歷每一頁的課程信息。代碼如下:
import requests
import xlsxwriter # 導入
def get_json(index):
"""
爬取課程的json數據
:param index: 頁碼 pageIndex 從1開始
:return: json數據
"""
url = "https://study.163.com/p/search/studycourse.json"
payload = {
"pageSize": 50,
"pageIndex": index,
"relativeOffset": 0,
"searchTimeType": -1,
"orderType": 5,
"priceType": -1,
"activityId": 0,
"qualityType": 0,
"keyword": "python"
} # 請求體
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
" (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36",
"accept": "application/json",
"content-type": "application/json",
"origin": "https://study.163.com"
} # 請求頭
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200: # 根據狀態碼判斷是否請求成功
content_json = response.json() # 獲取json數據
if content_json and content_json["message"] == "ok": # 判斷數據是否存在
return content_json
else:
print("請求數據失敗~")
return None
def get_content(content_json):
"""
獲取課程信息列表
:param content_json: 通過get_json函數獲取的json格式數據
:return: 課程數據
"""
if "result" in content_json:
return content_json["result"]["list"] # 返回課程數據列表
def save_excel(content, index):
"""
存儲到Excel
:param content: 課程內容
:param index: 索引值,從0開始
:return: None
"""
for num, item in enumerate(content):
# 因爲Excel第一行要寫入標題 所以row從1開始
row = 50 * (index - 1) + (num + 1)
# 行內容
work_sheet.write(row, 0, str(item["productId"]))
work_sheet.write(row, 1, str(item["courseId"])) # 以文本的形式在Excel單元格中顯示
work_sheet.write(row, 2, item["productName"])
work_sheet.write(row, 3, item["productType"])
work_sheet.write(row, 4, item["provider"])
work_sheet.write(row, 5, item["score"])
work_sheet.write(row, 6, item["scoreLevel"])
work_sheet.write(row, 7, item["learnerCount"])
work_sheet.write(row, 8, item["lessonCount"])
work_sheet.write(row, 9, item["lectorName"])
work_sheet.write(row, 10, item["originalPrice"])
work_sheet.write(row, 11, item["discountPrice"])
work_sheet.write(row, 12, item["discountRate"])
work_sheet.write(row, 13, item["imgUrl"])
work_sheet.write(row, 14, item["bigImgUrl"])
work_sheet.write(row, 15, item["description"])
def main(index):
"""
主函數
:param index: 索引值,從1開始
:return:
"""
content_json = get_json(index) # 取出json數據
content = get_content(content_json) # 取出課程信息
save_excel(content, index) # 存入Excel
if __name__ == '__main__': # 程序入口
print("*******************開始執行*******************")
work_book = xlsxwriter.Workbook("網易雲課堂Python課程數據.xlsx") # 創建excel文件
work_sheet = work_book.add_worksheet("first_sheet") # 創建sheet
# 行首標題
work_sheet.write(0, 0, "商品id")
work_sheet.write(0, 1, "課程id")
work_sheet.write(0, 2, "課程名稱")
work_sheet.write(0, 3, "課程類型")
work_sheet.write(0, 4, "機構名稱")
work_sheet.write(0, 5, "評分")
work_sheet.write(0, 6, "評分等級")
work_sheet.write(0, 7, "學習人數")
work_sheet.write(0, 8, "課程節數")
work_sheet.write(0, 9, "講師名稱")
work_sheet.write(0, 10, "原價")
work_sheet.write(0, 11, "折扣價")
work_sheet.write(0, 12, "折扣率")
work_sheet.write(0, 13, "課程小圖url")
work_sheet.write(0, 14, "課程大圖url")
work_sheet.write(0, 15, "課程描述")
total_page_count = get_json(1)["result"]["query"]["totlePageCount"]
for i in range(total_page_count):
main(i + 1) # i+1即爲頁碼
work_book.close() # 關閉excel寫入
print("*******************執行結束*******************")
運行程序會生成一個Excel表格,如圖所示。
2. 爬取在線課程MySQL版
對於使用爬蟲爬取到的數據,通常將其保存到文件或是數據庫中。這次將使用requests
模塊爬取網易雲課程,並使用pymysql模塊
將爬取到的數據存入到MySQL數據庫
中。爬取後效果如圖所示。
Python中操作mysql
步驟:
(1) 安裝第三方模塊pymysql
,命令如下:
pip install pymysql
(2) 在py文件中引入pymysql
模塊
from pymysql import *
(3) 建立連接
# 1.建立數據庫鏈接
# host: 連接的mysql主機 本機寫'localhost'
# port: 連接的mysql主機端口 默認是3306
# database: 數據庫的名稱
# user: 連接的用戶名
# password: 連接的密碼
# charset: 通信採用的編碼方式,推薦使用utf8
conn = connect(host="localhost", port=3306, database="wyy_spider", user="root", password="mysql", charset="utf8")
# 對象的方法如下:
# close()關閉連接
# commit()提交
# cursor() 返回Cursor對象,用於執行sql語句並獲得結果
(4) 創建cursor對象
# 用於執行sql語句 使用頻度最高的語句爲select、insert、update、delete
# 獲取Cursor對象: 調用Connection對象的cursor()方法
cs1 = conn.cursor()
# close()關閉
# execute(operation [, parameters ])執行語句,返回受影響的行數,主要用於執行insert、update、delete語句,也可以執行create、alter、drop等語句
# fetchone()執行查詢語句時,獲取查詢結果集的第一個行數據,返回一個元組
# fetchall()執行查詢時,獲取結果集的所有行,一行構成一個元組,再將這些元組裝入一個元組返回
2.1 增刪改查
向數據庫中添加數據,示例代碼如下:
from pymysql import * # 導入
if __name__ == '__main__':
# 1.建立連接
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
cs1 = conn.cursor()
# 3.操作數據
# 3.1 插入一條數據
count = cs1.execute("insert into teacher(name,age) values('Amo',18)")
print(count) # 打印受影響的行數
count = cs1.execute("insert into teacher(name,age) values('zy',16)")
print(count) # 打印受影響的行數
sql = "insert into teacher(name,age) values(%s, %s)"
# 第一個參數: 固定的sql語法
# 第二個參數: 列表 列表裏面的元素是由一個一個的元組組成
cs1.executemany(sql, [("Jerry", 35), ("Paul", 21), ("Jason", 26)])
# 3.2 插入多條數據
# 提交之前的操作
conn.commit()
# 關閉Cursor對象和Connection對象
cs1.close()
conn.close()
從數據庫中刪除數據,示例代碼如下:
from pymysql import * # 導入
if __name__ == '__main__':
# 1.建立連接
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
cs1 = conn.cursor()
# 3.操作數據
count = cs1.execute("delete from teacher where name='Jerry'")
print(count)
# 提交之前的操作
conn.commit()
# 關閉Cursor對象和Connection對象
cs1.close()
conn.close()
更改數據庫中的部分數據,示例代碼如下:
from pymysql import * # 導入
if __name__ == '__main__':
# 1.建立連接
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
cs1 = conn.cursor()
# 3.操作數據
count = cs1.execute("update teacher set age=18 where name='zy'")
print(count)
# 提交之前的操作
conn.commit()
# 關閉Cursor對象和Connection對象
cs1.close()
conn.close()
查詢數據庫中的數據,示例代碼如下:
from pymysql import * # 導入
if __name__ == '__main__':
# 1.建立連接
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
cs1 = conn.cursor()
# 3.操作數據
count = cs1.execute("select * from teacher where age > 18")
print(count)
# for i in range(count):
# # 獲取查詢的結果
# result = cs1.fetchone()
# print(result) # 打印結果 返回結果爲一個元組 ('Paul', 21)
result = cs1.fetchall()
# (('Paul', 21), ('Jason', 26))
print(result) # 返回的結果是一個元組 元組的元素由元組組成
# 提交之前的操作
conn.commit()
# 關閉Cursor對象和Connection對象
cs1.close()
conn.close()
2.2 代碼實現
實現將爬取信息寫入數據庫的功能,需要先創建數據庫,創建數據表,然後編寫代碼實現該功能。具體步驟如下:
(1) 創建數據庫。可以使用控制檯
或者MySQL可視化工具
創建一個名爲wyy_spider
的數據庫。如圖所示:
(2) 創建數據表。通過如下SQL語句來創建course
表:
create table course(
course_id bigint(20) not null,
product_id bigint(20) not null,
product_type int(11) not null,
product_name varchar(125) not null,
provider varchar(125) not null,
score float default null,
score_level int(11) default null,
learner_count int(11) default null,
lesson_count int(11) default null,
lector_name varchar(125) default null,
original_price float default null,
discount_price float default null,
discount_rate float default null,
img_url varchar(125) default null,
big_img_url varchar(125) default null,
description text,
primary key(course_id)) engine=InnoDB default charset=utf8;
(3) 最後代碼如下:
# -*- coding: utf-8 -*-
# @Time : 2020/4/11 16:44
# @Author : 我就是任性-Amo
# @FileName: 66.爬取在線課程.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/xw1680
from pymysql import *
import requests
import time # 導入
def get_json(index):
"""
爬取課程的json數據
:param index: 頁碼 pageIndex 從1開始
:return: json數據
"""
url = "https://study.163.com/p/search/studycourse.json"
payload = {
"pageSize": 50,
"pageIndex": index,
"relativeOffset": 0,
"searchTimeType": -1,
"orderType": 5,
"priceType": -1,
"activityId": 0,
"qualityType": 0,
"keyword": "python"
} # 請求體
headers = {
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/"
"537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
"accept": "application/json",
"content-type": "application/json",
"origin": "https://study.163.com"
} # 請求頭
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200: # 根據狀態碼判斷是否請求成功
content_json = response.json() # 獲取json數據
if content_json and content_json["message"] == "ok": # 判斷數據是否存在
return content_json
else:
print("請求數據失敗~")
return None
def get_content(content_json):
"""
獲取課程信息列表
:param content_json: 通過get_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
"""
sql = f'select course_id from course where course_id = {course_id}'
cs1.execute(sql)
course = cs1.fetchone()
if course:
return True
else:
return False
def save_to_course(course_data):
sql_course = """insert into course
values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
"""
cs1.executemany(sql_course, course_data)
def save_mysql(content):
course_data = []
for item in content:
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'],)
course_data.append(course_value)
save_to_course(course_data)
def main(index):
"""
主函數
:param index: 索引值,從1開始
:return:
"""
content_json = get_json(index) # 取出json數據
content = get_content(content_json) # 取出課程信息
save_mysql(content) # 存入數據庫
if __name__ == '__main__': # 程序入口
# 1.建立數據庫鏈接
# host: 連接的mysql主機 本機寫'localhost'
# port: 連接的mysql主機端口 默認是3306
# database: 數據庫的名稱
# user: 連接的用戶名
# password: 連接的密碼
# charset: 通信採用的編碼方式,推薦使用utf8
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
# 用於執行sql語句 使用頻度最高的語句爲select、insert、update、delete
# 獲取Cursor對象: 調用Connection對象的cursor()方法
cs1 = conn.cursor()
print("*******************開始執行*******************")
start = time.time()
total_page_count = get_json(1)['result']["query"]["totlePageCount"] # 獲取總頁數
for i in range(total_page_count):
main(i + 1)
conn.commit()
cs1.close()
conn.close()
print("執行結束")
end = time.time()
print(f"程序執行時間是{end - start}秒")
print("*******************執行結束*******************")
程序運行結果如圖所示,並且數據已經插入到mysql
數據庫中:
3. 使用多進程爬取在線課程MySQL版
如果爬取的數據內容較多,存在多個分頁,使用普通方式用時會較長。針對這種情況,可以使用多進程的方式來提高爬取數據和存入數據庫的效率。如果大家對多任務不熟悉的話,可以去觀看博主的另外一篇博客 Python進程和線程。運行效果如圖所示。
使用多任務爬取數據的時候,建議大家先將建表中的主鍵給去掉,先將數據爬取下來,然後再去數據庫中去重。否則可能會出錯,如下圖所示。
示例代碼如下:
from pymysql import *
import requests
import time # 導入
from multiprocessing import Pool
def get_json(index):
"""
爬取課程的json數據
:param index: 頁碼 pageIndex 從1開始
:return: json數據
"""
url = "https://study.163.com/p/search/studycourse.json"
payload = {
"pageSize": 50,
"pageIndex": index,
"relativeOffset": 0,
"searchTimeType": -1,
"orderType": 5,
"priceType": -1,
"activityId": 0,
"qualityType": 0,
"keyword": "python"
} # 請求體
headers = {
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/"
"537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
"accept": "application/json",
"content-type": "application/json",
"origin": "https://study.163.com"
} # 請求頭
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200: # 根據狀態碼判斷是否請求成功
content_json = response.json() # 獲取json數據
if content_json and content_json["message"] == "ok": # 判斷數據是否存在
return content_json
else:
print("請求數據失敗~")
return None
def get_content(content_json):
"""
獲取課程信息列表
:param content_json: 通過get_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
"""
sql = f'select course_id from course where course_id = {course_id}'
cs1.execute(sql)
course = cs1.fetchone()
if course:
return True
else:
return False
def save_to_course(course_data):
sql_course = """insert into course
values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
"""
cs1.executemany(sql_course, course_data)
def save_mysql(content):
course_data = []
for item in content:
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'],)
course_data.append(course_value)
save_to_course(course_data)
def main(index):
"""
主函數
:param index: 索引值,從1開始
:return:
"""
content_json = get_json(index) # 取出json數據
content = get_content(content_json) # 取出課程信息
save_mysql(content) # 存入數據庫
if __name__ == '__main__': # 程序入口
# 1.建立數據庫鏈接
# host: 連接的mysql主機 本機寫'localhost'
# port: 連接的mysql主機端口 默認是3306
# database: 數據庫的名稱
# user: 連接的用戶名
# password: 連接的密碼
# charset: 通信採用的編碼方式,推薦使用utf8
conn = connect(host="localhost", port=3306, database="wyy_spider",
user="root", password="mysql", charset="utf8")
# 2.創建cursor對象
# 用於執行sql語句 使用頻度最高的語句爲select、insert、update、delete
# 獲取Cursor對象: 調用Connection對象的cursor()方法
cs1 = conn.cursor()
print("*******************開始執行*******************")
start = time.time()
total_page_count = get_json(1)['result']["query"]["totlePageCount"] # 獲取總頁數
# for i in range(total_page_count):
# main(i + 1) 不使用多任務的方式
pool = Pool()
index_list = [i for i in range(total_page_count)]
# map(self, func, iterable, chunksize=None):
pool.map(main, index_list) # 執行多任務
pool.close() # 關閉進程池
pool.join() # 等待子進程結束
conn.commit()
cs1.close()
conn.close()
print("執行結束")
end = time.time()
print(f"程序執行時間是{end - start}秒")
print("*******************執行結束*******************")
運行結果如圖所示:
從運行結果可以看出,比之前的執行時間短了很多。至此今天的案例就到此結束了,另外筆者在這裏聲明,筆者寫文章只是爲了學習交流,以及讓更多學習Python基礎
的讀者少走一些彎路,節省時間,並不用做其他用途,如有侵權,聯繫博主刪除即可。編寫不易,請大家手留餘香~。