Python零基础速成班-第12讲-Python获取网络数据Socket,API接口,网络爬虫Crawler(制作弹幕词云)

Python零基础速成班-第12讲-Python获取网络数据Socket,API接口,网络爬虫Crawler(制作弹幕词云)

学习目标

  1. 获取网络数据Socket
  2. API接口
  3. 网络爬虫Crawler(制作弹幕词云)
  4. 课后作业(2必做)

友情提示:将下文中代码拷贝到JupyterNotebook中直接执行即可,部分代码需要连续执行。

1、Python获取网络数据

了解通过Python完成Socket通信的简单实例。

Socket定义:

  • Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
  • Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。
  • Socket把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket获取网络数据的四个步骤:

  1. 创建Socket
  2. 连接服务器
  3. 发送数据
  4. 关闭连接
1.1 创建Socket

socket.socket函数的前两个参数的默认值是socket.AF_INET和socket.SOCK_STREAM,创建TCP socket时可以直接写成socket.socket()。

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1.2 连接服务器

注意没有前缀http或https

s.connect(('www.baidu.com', 80))
1.3 发送数据

发送数据有两个方法send和sendall

  • send() 发送TCP数据,返回发送的字节大小。这个字节长度可能少于实际要发送的数据的长度。换句话说,这个函数执行一次,并不一定能发送完给定的数据,可能需要重复多次才能发送完成。
  • sendall() 发送完整的TCP数据,成功返回None,失败抛出异常
data = "something you want to send"
s.sendall(data) 
1.4 关闭连接

当连接不再需要时可以使用close关闭socket连接,关闭后的连接不能再进行任何操作。

s.close()
1.5 完整代码示例:获取百度网首页的数据

进阶提示:urllib库parse模块的urlparse可以帮我们实现URL地址各部分的抽取、合并以及链接转换。
如 https://www.baidu.com/s?wd=百度热搜
url.netloc转化为路径-> www.baidu.com
url.path转化为地址-> s?wd=百度热搜

import socket
from urllib.parse import urlparse
def get_url(url):
    url = urlparse(url)
    host = url.netloc
    path = url.path
    if path == "":
        path = "/"
        
    #创建socket连接并发送请求数据
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((host, 80))
    client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf-8"))
    #返回数据,设置为Byte格式,采用分步接收
    response = b""
    while True:
        data = client.recv(4096) #分步接收,每次4096字节
        if data:
            response += data
        else:
            break            
    response = response.decode("utf-8")
    #返回数组第一项为响应文本,第二项为响应内容即网页内容
    html_data = response.split("\r\n\r\n")[1]
    print(html_data)
    #关闭连接
    client.close()
#获取百度网首页的数据
if __name__ == '__main__':
    get_url("https://www.baidu.com")

2、API接口

在实际应用中,我们推荐使用Requests包来获取网络数据,包括API接口和爬虫。

Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库,Requests它会比urllib更加方便,可以节约我们大量的工作。

  1. 首先我们需要安装Requests包:pip install requests

  2. 大部分response.text返回的是Unicode格式,通常需要转换为utf-8格式,否则就是乱码。这时我们可以通过以下两种方式转码:

    1. 直接将内容转码:response.content.decode(“utf-8”)
    2. 设置编码格式后再输出内容:response.encoding = “utf-8” 再执行response.text
  3. 请求方式包括多种,GET请求、POST请求、PUT请求、DELETE请求等,可以理解为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,增,改,删4个操作。

请求类型请求类型的说明文档
GET请求GET请求用来查询数据,不会修改、增加数据,不会影响资源内容。
POST请求POST请求一般是对服务器的数据做改变,常用于数据的提交、新增操作。
PUT请求PUT请求的侧重点在于对于数据的修改操作。
DELETE请求DELETE请求一般用来删除某一个资源的。

2.1 通过实例学习Requests使用

例1,我们使用requests包来获取百度首页的数据,仅需三行代码,这里我们发送的是GET请求。
import requests
response = requests.get(url="https://www.baidu.com")
response.content.decode("utf-8")
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">登录</a>\');\r\n                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'
例2,我们通过post把数据提交到url地址,等同于以字典的形式提交form表单里面的数据。

进阶提示:
请求头中(http请求中的header部分)的编码方式content-type一般包括:

  1. application/x-www-form-urlencoded,当请求为GET时候,浏览器用该方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串加到url后面,用?分割,加载这个新的url。如:https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1
  2. multipart/form-data,当请求为POST时候,浏览器把form数据封装到http body中,然后发送到服务器,一般适用于文件传输。
  3. text/plain,以纯文本形式进行编码,其中不含任何控件或格式字符。
  4. application/json,一般用于POST请求,将json数据封装到http body中,然后发送到服务器,适用于数据交互。
import requests
url = 'http://httpbin.org/post'
mydata = {'name':'Jack','age':'28'}
myheaders = {"Content-Type":"application/json;charset=UTF-8"}
response = requests.post(url,data=mydata,headers=myheaders)
print(response.content.decode("utf-8"))
{
  "args": {}, 
  "data": "name=Jack&age=28", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Content-Length": "16", 
    "Content-Type": "application/json;charset=UTF-8", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.26.0", 
    "X-Amzn-Trace-Id": "Root=1-629827a5-57a465dd45bdeef31a0951bc"
  }, 
  "json": null, 
  "origin": "61.139.91.108", 
  "url": "http://httpbin.org/post"
}
例3,文件上传,我们在D盘根目录创建一个test.txt,将其上传至服务器。

文件会转为Byte格式,放入files字段中进行传输。

import requests
url = "http://httpbin.org/post"
files= {"files":open("D://test.txt","rb")}
response = requests.post(url,files=files)
print(response.content.decode("utf-8"))
{
  "args": {}, 
  "data": "", 
  "files": {
    "files": "data:application/octet-stream;base64,MjAyMi0wNS0zMSAxMToxNTo0NSwzMjIgLSAgV0FSTklORyAtICBFcnJvcjogw7vT0NXStb3OxLz+u/K2wcihzsS8/sqnsNwNCg=="
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Content-Length": "218", 
    "Content-Type": "multipart/form-data; boundary=e3e837dec7b537789994f8e32e739be0", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.26.0", 
    "X-Amzn-Trace-Id": "Root=1-62982b13-1dd468c06ce969d056a88985"
  }, 
  "json": null, 
  "origin": "61.139.91.108", 
  "url": "http://httpbin.org/post"
}
例4,超时设置,通过timeout参数可以设置超时的时间,并通过requests.exceptions抛出报错。

设置必须在100ms内收到响应,不然或抛出ReadTimeout异常。

import requests
from requests.exceptions import ReadTimeout
try:
    response = requests.get("http://httpbin.org/get", timeout=0.1)
    print(response.status_code)
except Exception as ex:
    print("请求超时,文本为:",repr(ex))
请求超时,文本为: ConnectTimeout(MaxRetryError("HTTPConnectionPool(host='httpbin.org', port=80): Max retries exceeded with url: /get (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002040231F970>, 'Connection to httpbin.org timed out. (connect timeout=0.1)'))"))
例5,获取cookie,会话session维持

Cookie 能够保存有关访问者的信息。更概括地说,Cookie 是一种保持 Web 应用程序连续性的方法。因此 Cookie 的作用就类似于名片,它提供了相关的标识信息,可以帮助应用程序确定如何继续执行。例如一些要求用户登录的站点则可以通过 Cookie 来确定您是否已经登录过,这样您就不必每次都输入账号密码。

cookie和session区别:

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2. cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。
  3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。
  4. 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
import requests
response = requests.get('https://www.baidu.com')
print(response.cookies)
for key,value in response.cookies.items():
    print(key,'==',value)
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ == 27315

cookie的一个作用就是可以用于模拟登陆,做会话维持。如下例,我们给服务器上的会话设置cookie,接下来获取会话的cookie。

import requests
session = requests.session()
session.get('http://httpbin.org/cookies/set/number/654321')
response = session.get('http://httpbin.org/cookies')
print(response.text)
{
  "cookies": {
    "number": "654321"
  }
}

2.2 通过API接口获取数据

API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程,而又无需访问源码,或理解内部工作机制的细节。

例1,不带任何参数的API接口,历史上的今天API接口,请求类型GET
import requests
import json
response = requests.get("https://api.oioweb.cn/api/common/history")
r = json.loads(response.text)
for index,info in enumerate(r["result"],1):
    print("{}:{}-{}".format(index,info["year"],info["title"]))

1:290-西晋开国皇帝晋武帝司马炎逝世
2:762-唐朝皇帝唐肃宗李亨逝世
3:1375-明朝政治家刘伯温逝世
4:1787-德国物理学家乔治·欧姆诞生于德国巴伐利亚埃尔朗根城
5:1940-中华民国国军将军张自忠在与日军战斗中壮烈殉国
6:1941-《解放日报》在延安创刊
7:1947-第二次国共内战孟良崮战役结束
8:1951-日本声优石冢运升出生
9:1953-美国男演员皮尔斯·布鲁斯南出生
10:1958-美国第二通讯社合众国际社建成
11:1958-中国“大跃进”运动全面展开
12:1960-梅曼在休斯研究实验室首次产生光学雷射
13:1969-苏联宇宙飞船到达金星
14:1997-中国当代散文家汪曾祺逝世
15:2013-英格兰著名球星贝克汉姆通过英足总官网宣布退役

例2,带参数的API接口,新华字典查字,参数text为要查的汉字
import requests
r = requests.get(url="https://api.oioweb.cn/api/txt/dict?text=躺")
r.encoding="utf-8"
print(r.text)

{“code”:200,“result”:{“hanzi”:“躺”,“pinyin”:“tǎng”,“bihua”:“15”,“bushou”:“身”,“wubi”:“”,“basic_explain”:[“躺”,“tǎng”,“笔画数:15”,“部首:身”,“笔顺编号:325111324325251”],“detail_explain”:[“详细字义”,“◎ 躺 tǎng”,“〈动〉”,“同本义 [lie;recline]”,“这无耻的畜生想必是躺尸了。——清· 忧患余生《邻女语》”,“又如:躺在床上;躺着歇歇;躺尸;躺桥”,“停止劳动或努力 [rest]。如:不要躺在过去的成绩上睡大觉”,“引伸指物体平放或倒伏在地 [lie flat]。如:荒草躺倒在烂泥里”,“死的婉辞 [die]”,“先母躺了下来,还是很热闹的。——《二十年目睹之怪现状》”],“words”:"躺倒 躺卧 躺椅 "},“msg”:“success”}

例3,返回JSON格式的API接口,随机输出毒鸡汤

我们通过JSON包来处理JSON格式的数据

import requests
import json
r = requests.get("https://api.oioweb.cn/api/SoulWords")
r.content.decode("utf-8")
print(r.text)
joke = json.loads(r.text)
print("API状态码:",joke["code"])
print(joke["result"]["content"])
{"code":200,"result":{"content":"虽然我长得丑,但是买了漂亮衣服,我就可以丑的漂亮。"},"msg":"success"}
API状态码: 200
虽然我长得丑,但是买了漂亮衣服,我就可以丑的漂亮。
例4,返回JSON格式(多值)的API接口,查询域名示范已被注册,参数domain为要查询的域名

我们通过pprint包来格式化打印JSON格式的结果,width=10表示超过10个字节即按照pprint定义的格式打印

import requests
import pprint
r = requests.get("https://api.oioweb.cn/api/site/reg?domain=abcyyyccc.cn")
r.content.decode("utf-8")
result = json.loads(r.text)
pprint.pprint(result,width=10)
{'code': 200,
 'msg': 'success',
 'result': False}

2.3 通过API接口获取天气预报小型项目开发实例

2.3.1 项目目标:实现某个城市近三天天气预报:日出日落、月升月落、最高最低温度、天气白天和夜间状况、风力、风速、风向、相对湿度、大气压强、降水量、降水概率、露点温度、紫外线强度、能见度等。(本次项目只取最高气温、最低气温、天气概览、湿度四个字段)
2.3.2 前期准备:
1. 天气预报服务商:和风天气 https://www.qweather.com
2. API接口文档:https://dev.qweather.com/docs/api/weather
3. API接口开发KEY申请:需要注册登录并申请免费的开发KEY https://id.qweather.com
4. 项目所需要的Package包:
    ① Requests包,用来调用API接口
    ② JSON包,用来处理JSON格式数据
    ③ Pandas包,用来快速处理数据
2.3.3 程序第一步:首先获取天气预报的城市的id(我们以都江堰市为例),Key为我自己申请的开发Key,后期建议自行申请。

城市API接口为 https://geoapi.qweather.com/v2/city/lookup
传入参数location为城市中文或英文名字
传入参数key为我们申请的开发KEY

import json
import numpy as np
import pandas as pd
import requests
key = "3746c837ff16452b90b5ef2c7533b758"#这里是我们申请的开发KEY,后期建议自行申请
city = requests.get("https://geoapi.qweather.com/v2/city/lookup?location={}&key={}".format("都江堰",key))
print(city.text)
#获取id
cityjson = json.loads(city.text)
print("城市id是:",cityjson["location"][0]["id"])
{"code":"200","location":[{"name":"都江堰","id":"101270111","lat":"30.99114","lon":"103.62789","adm2":"成都","adm1":"四川省","country":"中国","tz":"Asia/Shanghai","utcOffset":"+08:00","isDst":"0","type":"city","rank":"33","fxLink":"http://hfx.link/3tu1"}],"refer":{"sources":["QWeather"],"license":["commercial license"]}}
城市id是: 101270111
2.3.4 程序第二步:获取都江堰市最近三天天气预报数据。

近三天天气预报接口为 "https://devapi.qweather.com/v7/weather/3d
传入参数location为城市id
传入参数key为我们申请的开发KEY

wether = requests.get("https://devapi.qweather.com/v7/weather/3d?location={}&key={}".format("101270111",key))
weatherjson = json.loads(wether.text)
print(weatherjson)
{'code': '200', 'updateTime': '2022-06-06T12:35+08:00', 'fxLink': 'http://hfx.link/3tu1', 'daily': [{'fxDate': '2022-06-06', 'sunrise': '06:02', 'sunset': '20:07', 'moonrise': '11:37', 'moonset': '01:17', 'moonPhase': '峨眉月', 'moonPhaseIcon': '801', 'tempMax': '29', 'tempMin': '19', 'iconDay': '104', 'textDay': '阴', 'iconNight': '104', 'textNight': '阴', 'wind360Day': '0', 'windDirDay': '北风', 'windScaleDay': '1-2', 'windSpeedDay': '3', 'wind360Night': '0', 'windDirNight': '北风', 'windScaleNight': '1-2', 'windSpeedNight': '3', 'humidity': '64', 'precip': '0.0', 'pressure': '890', 'vis': '25', 'cloud': '25', 'uvIndex': '11'}, {'fxDate': '2022-06-07', 'sunrise': '06:02', 'sunset': '20:07', 'moonrise': '12:34', 'moonset': '01:47', 'moonPhase': '上弦月', 'moonPhaseIcon': '802', 'tempMax': '29', 'tempMin': '18', 'iconDay': '300', 'textDay': '阵雨', 'iconNight': '350', 'textNight': '阵雨', 'wind360Day': '0', 'windDirDay': '北风', 'windScaleDay': '1-2', 'windSpeedDay': '3', 'wind360Night': '0', 'windDirNight': '北风', 'windScaleNight': '1-2', 'windSpeedNight': '3', 'humidity': '69', 'precip': '1.0', 'pressure': '890', 'vis': '23', 'cloud': '60', 'uvIndex': '8'}, {'fxDate': '2022-06-08', 'sunrise': '06:02', 'sunset': '20:07', 'moonrise': '13:33', 'moonset': '02:16', 'moonPhase': '盈凸月', 'moonPhaseIcon': '803', 'tempMax': '26', 'tempMin': '17', 'iconDay': '300', 'textDay': '阵雨', 'iconNight': '350', 'textNight': '阵雨', 'wind360Day': '0', 'windDirDay': '北风', 'windScaleDay': '1-2', 'windSpeedDay': '3', 'wind360Night': '0', 'windDirNight': '北风', 'windScaleNight': '1-2', 'windSpeedNight': '3', 'humidity': '81', 'precip': '1.0', 'pressure': '889', 'vis': '16', 'cloud': '55', 'uvIndex': '4'}], 'refer': {'sources': ['QWeather', 'NMC', 'ECMWF'], 'license': ['no commercial use']}}
获取第一天的天气
print("最低气温:",weatherjson['daily'][0]['tempMin'])
print("最高气温:",weatherjson['daily'][0]['tempMax'])
print("天气情况:",weatherjson.get('daily')[0].get('textDay'))
print("湿度:",weatherjson.get('daily')[0].get('humidity'))
最低气温: 19
最高气温: 29
天气情况: 阴
湿度: 64
2.3.5 程序第三步: 整理数据,形成以下数据结构,并通过Pandas展示。
{
"tempMin":[day1,day2,day3]
"tempMax":[day1,day2,day3]
"textDay":[day1,day2,day3]
"humidity":[day1,day2,day3]
}
needs = ["tempMin","tempMax","textDay","humidity"]#需要取值的字段
weatherdict={need:[] for need in needs}#初始化数据结构{'tempMin': [], 'tempMax': [], 'textDay': [], 'humidity': []}
for daily in weatherjson["daily"]:#循环近三天天气
    for need in needs:#将需要取值的字段添加到对应数组中
        weatherdict[need].append(daily[need])
weatherdict
{'tempMin': ['19', '18', '17'],
 'tempMax': ['29', '29', '26'],
 'textDay': ['阴', '阵雨', '阵雨'],
 'humidity': ['64', '69', '81']}
Pandas展示
index=[i for i in range(1,4)]
index
[1, 2, 3]
w =pd.DataFrame(weatherdict,index=["第一天","第二天","第三天"])
w
tempMintempMaxtextDayhumidity
第一天192964
第二天1829阵雨69
第三天1726阵雨81

3、网络爬虫Crawler(制作弹幕词云)

网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,可以自动化浏览网络中的信息,当然浏览信息的时候需要按照我们制定的规则进行,这些规则我们称之为网络爬虫算法。使用Python可以很方便地编写出爬虫程序,进行互联网信息的自动化检索。

3.1 通过网络爬虫制作弹幕词云小型项目开发实例

3.1.1 项目目标:通过网络爬虫获取某站番剧弹幕,进行数据整理、分词、生成弹幕词云。
3.1.2 前期准备:(网址中的毕里毕里请大家自行替换)
1. 网络爬虫获取弹幕网页地址: 番剧鲁邦三世 https://www.毕里毕里.com/bangumi/play/ss39468
2. 项目所需要的Package包:
    ① Requests包,用来爬取网页数据
    ② bs4.BeautifulSoup包,HTML/XML解析器,用来处理网页数据
    ③ jieba包,用来分词
    ④ wordcloud包,用来生成词云
    ⑤ matplotlib.pyplot包,用来展示弹幕词云
3.上述包如果不包含在Anacoda3中,则需要通过"pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名"进行安装。(重要)
    ① pip install -i https://pypi.tuna.tsinghua.edu.cn/simple BeautifulSoup
    ② pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba
    ③ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple wordcloud  #手动安装地址https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud

4.pip install --upgrade Pillow 升级最新的作图包Pillow避免出现WordCloud中AttributeError: 'TransposedFont' object has no attribute 'getbbox'错误。
3.1.3 程序第一步:获取弹幕网址并进行爬取。

获取弹幕网址操作顺序如下:

  1. 首先点进一个视频网页如https://www.毕里毕里.com/bangumi/play/ss39468 ,点击F12,进入Network获取监测页面,然后一定要点击播放视频,我们选择Fetch/XHR,在资源过滤Filter中输入cid,然后任意点击一个进入即可。
  2. cid就是该剧弹幕的id号,这个id是唯一的,获取弹幕网址固定xml格式是:https://comment.毕里毕里.com/视频的cid.xml 。
  3. 以番剧鲁邦三世为例,我们最终获取到弹幕的网址是:https://comment.毕里毕里.com/430717173.xml 。

danmu1

接下来,根据弹幕网址,爬取弹幕数据。

import requests
crawler = requests.get("https://comment.毕里毕里.com/430717173.xml")
crawler.encoding='utf-8'
crawler.text
3.1.3 程序第二步:数据整理、分词。
  1. 我们发现爬取下来的弹幕XML均有规律,即都是以标签"d"开头,所以我们只需用Beautifulsuop来选取所有标签为"d"的就可以。
  2. 我们将d标签数据转化为弹幕数组list格式。
  3. 数据清洗:统一英文大小写,去掉空格,去掉重复及一些不必要的字符等。
  4. 分词并去掉单字节的内容。
from bs4 import BeautifulSoup #HTML/XML解析器,处理网页数据
import jieba #分词
soup = BeautifulSoup(crawler.text,"lxml")
results = soup.find_all("d")#找出所有"d"
comments = [comment.text for comment in results]#转化为弹幕list,注意,b站弹幕提取上线是1000条,大于则会随机选取1000条
comments = [comment.upper() for comment in comments]#统一英文大小写
comments = [comment.replace(' ','') for comment in comments]#去掉空格
comments = [comment for comment in set(comments) if comment not in ["!!","??",",。"]]#去掉重复及一些不必要的字符
danmu = ''.join(comment for comment in comments)#合成一个字符串
ciyun = list(jieba.cut(danmu))#分词
ciyun = [word for word in ciyun if len(word)>1]#去掉单字节的内容
ciyun[0:10]#因为数据量大,我们取前十个
['回忆', '可能', '别说', '什么', '绝对', '没死', '哈德森', '太太', '我姐', '区区']
3.1.4 程序第三步:生成弹幕词云并展示。
import wordcloud #生成词云
from matplotlib import pyplot as plt #展示弹幕词云
wc = wordcloud.WordCloud(width=1000, font_path='simfang.ttf',height=800)#设定词云画的大小字体,一定要设定字体,否则中文显示不出来
wc.generate(' '.join(ciyun)) #合成一个字符串后放入词云画布中
plt.imshow(wc) #展示词云
<matplotlib.image.AxesImage at 0x2aee43b8a30>

ciyun1

3.2 接下来将上述程序打包为一个函数,再生成名侦探柯南的弹幕词云

我们先补充一下wordcloud包,词云图片输出的常用参数有:
  • width 词云图片宽度,默认400像素
  • height 词云图片高度 默认200像素
  • background_color 词云图片的背景颜色,默认为黑色background_color=‘white’
  • font_step 字号增大的步进间隔 默认1号
  • font_path 指定字体路径 默认None,对于中文可用font_path=‘msyh.ttc’
  • mini_font_size 最小字号 默认4号
  • max_font_size 最大字号 根据高度自动调节
  • max_words 最大词数 默认200
  • stop_words 不显示的单词 stop_words={“python”,“java”}
  • scale 默认值1。值越大,图像密度越大越清晰
  • prefer_horizontal:默认值0.90,浮点数类型。表示在水平如果不合适,就旋转为垂直方向
  • relative_scaling:默认值0.5,浮点型。设定按词频倒序排列,上一个词相对下一位词的大小倍数。有如下取值:“0”表示大小标准只参考频率排名,“1”如果词频是2倍,大小也是2倍
  • mask 指定词云形状图片,默认为矩形
import requests
from bs4 import BeautifulSoup
import jieba
import wordcloud
from matplotlib import pyplot as plt
def danmu(url:"弹幕XML地址")->"输出弹幕云":
    #爬取弹幕数据
    crawler = requests.get(url)
    crawler.encoding='utf-8'
    #数据整理、分词
    soup = BeautifulSoup(crawler.text,"lxml")
    results = soup.find_all("d")
    comments = [comment.text for comment in results]
    comments = [comment.upper() for comment in comments]
    comments = [comment.replace(' ','') for comment in comments]
    comments = [comment for comment in set(comments) if comment not in ["!!","??",",。"]]
    danmu = ''.join(comment for comment in comments)
    ciyun = list(jieba.cut(danmu))
    ciyun = [word for word in ciyun if len(word)>1]
    #生成弹幕词云并展示,font_path指定字体路径,scale指定图像清晰度,数值越大越清晰,程序耗时越久
    wc = wordcloud.WordCloud(width=1200, font_path='simfang.ttf',height=800,scale=5)
    wc.generate(' '.join(ciyun))
    plt.imshow(wc)
danmu("https://comment.毕里毕里.com/483236581.xml")#名侦探柯南

ciyun2

4、课后作业,答案在下一讲

1、编程实践项目:利用百度智能云API服务制作一个手机号码归属地查询API接口。

  1. 目标要求:输入手机号,查询手机号码归属地信息、包含省市区、运营商、区号等信息。
  2. API接口地址:https://api.oioweb.cn/api/common/teladress
  3. 请求方式:GET/POST
  4. 请求示例GET:https://api.oioweb.cn/api/common/teladress?mobile=13988888888
您的代码:

2、编程实践项目:利用网络爬虫,爬取文件信息,生成文件的词云图片。

  1. 目标要求:从 http://www.gov.cn/zhengce/2021-02/21/content_5588098.htm 中获取《关于全面推进乡村振兴加快农业农村现代化的意见》网页源码,进行数据整理、分词、生成词云图片并展示。
  2. 提示:
    1. 爬取文件网页源码,转化为utf-8格式。
    2. 寻找文件规律,使用BeautifulSoup查询转化,输出数组,文件信息是以段落标签"p"开头的,不需要去除空格和重复。
    3. 分词,去掉单字符和内容为"\r\n"的单词。
    4. 生成词云图片并展示(图片长度1200,高度800,清晰度3,背景底色白色,字体"msyh.ttc")。
    5. 需要使用requests、BeautifulSoup、jieba、wordcloud、matplotlib包,需要自行安装。
您的代码:

5、上一讲Python零基础速成班-第11讲-Python日志Logging,小游戏设计game of life 课后作业及答案

1、写一个计算程序,计算一个list列表[3,5,0,4.5,0.8,7,14]的第i项元素与第j项元素相除的结果,使用try/catch,对可能遇到除数为0,i,j超出数组界限等错误进行输出。不断完善你的程序,使其可以正常执行不报错。i,j通过input()输入。

list = [3,5,0,4.5,0.8,7,14]
try:
    i=int(input("请输入第i项:\n"))
    j=int(input("请输入第j项:\n"))
    if j ==0:
        raise ZeroDivisionError("除数不能为0")
    if i > len(list) or j > len(list):
        raise IndexError("输入超出数组范围")
    print(list[i]/list[j])
except Exception as ex:
    print("异常:"+repr(ex))
请输入第i项:
3
请输入第j项:
2
异常:ZeroDivisionError('float division by zero')

2、设计一个函数,统计并输出0至n相加之和,n由input输入。在函数执行前输出INFO日志(“日期时间—日志级别—统计0至n相加之和程序开始!”)当n > 100万时,输出ERROR日志(“日期时间—日志级别—n大于100万!”),仅输出日志不影响程序。

import logging
logging.basicConfig(level=logging.INFO,encoding='utf-8',format='%(asctime)s -  %(levelname)s -  %(message)s')
def sums(n):
    logging.info("统计0至%s相加之和程序开始!" %n)
    if n >1000000:
        logging.error("%s大于100万!" %n)
    total = 0
    for i in range(n+1):
        total+=i
    return total
n = int(input("请输入n的值\n:"))
print(sums(n))
请输入n的值
:1000001


2022-06-07 14:41:14,306 -  INFO -  统计0至1000001相加之和程序开始!
2022-06-07 14:41:14,307 -  ERROR -  1000001大于100万!


500001500001
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值