前言:
当前我们对“python源码剖析 豆瓣”大概比较重视,你们都想要知道一些“python源码剖析 豆瓣”的相关内容。那么小编也在网络上网罗了一些关于“python源码剖析 豆瓣””的相关知识,希望小伙伴们能喜欢,咱们快快来了解一下吧!用Python爬取中国医生电影评论生成词云并实现数据可视化(内附源码)
今日目标:爬取豆瓣电影中国医生评论实现数据可视化
前言
前段时间,主旋律电影《中国医生》上线,大家有没有去看呢?反正我去看了,有点感人(其实哭得稀里哗啦)。看完后,内心感概万分,回到家缓了好久。看了电影的海报画面,想着可以爬一爬大家对电影的评论,正好给大家写文了。于是,利用下班时间给大家做了这个爬虫项目。废话不多了,直接开整。
工具使用
开发环境
系统:Windows10 64位
Python版本:Python3.7
IDE:Pycharm
第三方库:selenium lxml re wordcloud PIL numpy jieba matplotlib
代码演示
饼图
词云生成
柱状图生成
项目思路分析
1 获取网址规律
可以看到 start 和 status是变化的关键
在这个页面可以通过xpath获取地址网页 评论详情 和评分
地址网页:
评论详情:
评分 :
2 打开地址网页,获取地址信息
有些没有地址信息 所有需要获取全部 后期通过数据处理获取有地址信息的
3 把获取的数据进行解析 分别存放三个文件
4 通过读取相应的文件生成相应的图表
项目难点分析
1 滑块验证
这个参考代码里面的滑块验证的方法
通过像素对比找到缺口
移动一段距离 之后速度变化慢慢往前面走 到达缺口就能够验证成功
2 切换iframe
# 切换iframedriver.switch_to.frame(1)
需要切换iframe才能找到滑块和输入账号 密码 的元素位置
3 显示等待
wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="profile"]/div/div[2]')))
等待元素出现才进行下一步的处理
4 数据处理
出现不合法的数据 比如 该用户已经主动注销帐号
判断源代码中是否存在 如果存在就跳过 防止等待时间过长 退出程序
if driver.page_source.__contains__("`该用户已经主动注销帐号`"):continue
5 抓取思维
采取先抓大再抓小
这样可以确定几个元素是相对应的
循环的时候会再次使用xpath 此时的xpath写法
需要加一个 .
item = {"href": email_detail.xpath('./div/a/@href'),"detail": email_detail.xpath("./div[2]/p/span//text()"),"rate": email_detail.xpath("./div[2]/h3/span[2]/span[2]/@class")}
6 json模块默认编码
默认:ascii码 为了中文的正确显示 需要传递参数ensure_ascii
f.write(json.dumps(email, ensure_ascii=False) + ",\n")
7 词云图的生成
按照图片格式只需要添加一个参数即可mask
# graph 图片对象word_cloud = WordCloud(font_path="simsun.ttc",background_color="white",mask=graph, # 指定词云的形状)
8 柱状图和饼图
难点在于json文件读取
循环获取的data 然后通过列表构建echarts需要的数据格式
$.getJSON("json_file/rate.json", function(data) {var x_data = [];for (var i = 0; i < data.length; i++) {console.log(data[i]);for(var key in data[i]){ // 输出字典元素,如果字典的key是数字,输出时会自动按序输出hello = {value: data[i][key], name: key+"星"}x_data[i] = hello;}};源码展示
词云图
# 词云生成import jiebaimport numpy as npfrom wordcloud import WordCloudimport matplotlib.pyplot as pltfrom PIL import Imagetext = open("json_file/detail.text",encoding='utf8').read()text = text.replace('\n',"").replace("\u3000","")text_cut = jieba.lcut(text)text_cut = ' '.join(text_cut)# 主要区别background = Image.open("image/mmexport1626868510673.jpg")graph = np.array(background)word_cloud = WordCloud(font_path="simsun.ttc", background_color="white", mask=graph, # 指定词云的形状 )word_cloud.generate(text_cut)plt.subplots(figsize=(12,8))plt.imshow(word_cloud)plt.axis("off")plt.show()
滑块验证
def slide(driver): """滑动验证码""" # 切换iframe driver.switch_to.frame(1) # 找到滑块 block = driver.find_element_by_xpath('//*[@id="tcaptcha_drag_button"]') # 找到刷新 reload = driver.find_element_by_xpath('//*[@id="reload"]') while True: # 摁下滑块 ActionChains(driver).click_and_hold(block).perform() # 移动 ActionChains(driver).move_by_offset(180, 0).perform() # 获取位移 tracks = get_tracks(30) # 循环 for track in tracks: # 移动 ActionChains(driver).move_by_offset(track, 0).perform() # 释放 ActionChains(driver).release().perform() # 停一下 time.sleep(2) # 判断 if driver.title == "登录豆瓣": print("失败...再来一次...") # 单击刷新按钮刷新 reload.click() # 停一下 time.sleep(2) else: break
打开文件获取清洗数据
def get_file(): # 打开文件获取清洗数据 f = open('data.json', 'r', encoding="utf-8") hello = f.read() # 地址列表 评分列表 评论内容列表 address_ = [] rate_ = [] detail_ = [] # 按换行符进行 for i in hello.split("\n"): try: # 转换为字典 data = eval(i[:len(i) - 1]) # 获取评论详细内容 detail = data.get("detail")[0] # 获取评分 rate = re.findall("(\d{1})\d", data.get("rate")[0])[0] # 获取地址 address = ".".join(re.findall("常居: ([\u4e00-\u9fa5]{2})", "".join(data.get("address")))) # 地址存在则添加到地址列表中 if address: address_.append(address) # 把评分添加到评分列表中 rate_.append(rate) # 把评论添加到评论列表中 detail_.append(detail) except: continue
获取评分和唯一地址
# 获取评分和地址的唯一 rate_set = set(rate_) address_set = set(address_) # 写入 评分json with open("json_file/rate.json", 'w', encoding="utf-8") as file: rate_json_list = [] for r in rate_set: # 获取评分频次并且构造字典 rate_json = {r: rate_.count(r)} rate_json_list.append(rate_json) file.write(json.dumps(rate_json_list, ensure_ascii=False))
写入地址json文件
# 写入地址json文件 with open("json_file/address.json", 'w', encoding="utf-8") as file: address_json_list = [] for a in address_set: # 获取地址频次并且构造字典 address_json = {a: address_.count(a)} address_json_list.append(address_json) file.write(json.dumps(address_json_list, ensure_ascii=False))
写入详情文件夹
# 写入详情文件夹 with open("json_file/detail.text", 'w', encoding="utf-8") as file: detail = "".join(detail_).replace("\n", "") file.write(detail)def get_json(data, driver, f): Html = etree.HTML(data) # 通过xpath获取响应的板块 email_details = Html.xpath('//*[@id="comments"]/div') items = [] # 循环板块 获取每一个板块里面的数据 for email_detail in email_details: # 地址页的地址 评论内容 评分呢 item = { "href": email_detail.xpath('./div/a/@href'), "detail": email_detail.xpath("./div[2]/p/span//text()"), "rate": email_detail.xpath("./div[2]/h3/span[2]/span[2]/@class") } items.append(item)
循环列表获取地址网址
# 循环列表获取地址网址 爬取地址 for email in items: # 如果网址为控则跳过 if not email.get("href"): continue driver.get(email.get("href")[0]) # 如果评论用户已经注册则跳过 if driver.page_source.__contains__("该用户已经主动注销帐号"): continue print(email.get("href")) wait = WebDriverWait(driver, 10) # 隐士等待 等待数据板块出现进行下一步 wait.until( EC.presence_of_element_located((By.XPATH, '//*[@id="profile"]/div/div[2]')) ) # 获取地址 email["address"] = etree.HTML(driver.page_source).xpath('//*[@id="profile"]/div/div[2]/div[1]/div//text()') # 整体数据写入初始文件中 f.write(json.dumps(email, ensure_ascii=False) + ",\n")
主程序
def main(user, pwd): """主程序""" f = open("data.json", "w", encoding="utf-8") f.write("[") url = "; # 驱动路径 driver_file = os.path.join(os.path.dirname(__file__), "driver_exe", "chromedriver.exe") # 声明驱动 driver = webdriver.Chrome(executable_path=driver_file) driver.get(url) driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]').click() driver.find_element_by_xpath('//*[@id="username"]').send_keys(user) driver.find_element_by_xpath('//*[@id="password"]').send_keys(pwd) driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a').click() # 停一下,等待出现 time.sleep(2) # 滑动验证码 slide(driver) print("成功") type_mile = ["P", "F"] for type_ in type_mile: if type_mile == "P": index_mile = 480 else: index_mile = 180 for i in range(0, index_mile, 20): url = f"{i}&limit=20&status={type_}&sort=new_score" print(url) driver.get(url) # 解析数据 get_json(driver.page_source, driver, f) f.write("]") driver.quit() get_file() # 所有数据获取完毕之后推出浏览器 解析数据 # 解析完毕并且创建解析之后数据的json文件 f.close()if __name__ == '__main__': user = input("请输入你的账号:") pwd = input("请输入你的密码:") main(user, pwd)
仅供学习,爬虫使用需谨慎!
希望可以得到各位的一键三连,感谢各位支持!
祝大家学习python顺利!
如果有正在跟我一样的自学的朋友,需要我本篇的代码或者其他的Python学习资料可以转发此文私信我(私信发我“中国医生”)
标签: #python源码剖析 豆瓣