龙空技术网

Python爬取豆瓣电影中国医生,爬虫之路,永无止境(附源码)

小三十三 436

前言:

当前我们对“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源码剖析 豆瓣