前言
前面写过3篇文章,分别介绍了反爬措施,JS逆向+ajax获取数据,以及正则表达式匹配开头、结尾、中间的用法。第3篇算是本文 Python Selenium 爬虫实现方案的子集,大家可以参照阅读。
另外本意是“攻守”,不知道为何输入法给的都是“功守道”,前面没有注意全都写错了。已经纠正重新发布。
网站的反爬措施分析
JS逆向,ajax获取数据
正则表达式 - 匹配开头、结尾、中间
在这个爬虫案例中,我遇到的最难部分甚至都不是破解各种反爬措施和梳理网站逻辑,而是正则表达式的书写、测试和验证,在后者上耗费的心力远超前者。
js 逆向方案,只需要从 js 代码中匹配参数名、函数名,正则使用范围还相对有限。
而在本文提到的 Selenium 方案中,因为需要从页面的静态源代码中提取数据,而其中又夹杂了很多网站为反爬做的通过不同 css 样式包裹的假数据 —— 真中有假,假中有真。这样就需要做很多替换处理,而替换的前提正是匹配 —— 如何正确匹配,并且高效匹配 —— 是这个方案能够成功的关键。
正文
龙套登场
因为数据是经过渲染后才展示,直观感知就是页面打开后不是第一时间就能看到数据,以及通过浏览器查看的源代码中找不到数据。
无论标准的 request 还是 Scrapy 提供的 request,能够拿到的都只是这个找不到数据的网页源代码,像下面这样,只有包含样式的3个 Table,没有数据。巧妇难为无米之炊,没有米(数据),何来炊(提取)。
而Selenium 的不同(牛逼)之处是,他提供了1个属性 page_source,这个page_source 就能够拿到渲染后的页面源代码。我们可以把他保存到本地。如下图。可以看到每个Table 都已经填充了数据。
在 网站的反爬措施分析 这篇文章中,我们已经讲过网站针对 Selenium 做的反爬措施,在代码中都需要相应地解决掉。完整代码如下。
apath = r'F:\Python\Scrapy\S007_AQI\S007_AQI\.wdm\drivers\chromedriver\win32\108.0.5359\chromedriver.exe'
url = request.url
if 'daydata' in url:
city = request.meta['city']
month = request.meta['month']
options = webdriver.ChromeOptions()
options.add_argument(r'ignore-certificate-errors')
options.add_argument(r"--headless")
options.add_argument(
r'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36')
options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
driver = webdriver.Chrome(service=Service(apath), options=options)
# Selenium 模式也会被网站监测,所以需要在网站的监测代码执行前,先执行下面的代码调整navigator属性
# 使用 headless 无头模式的话,还需要配置 plugins
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5],
})
"""
})
driver.get(url)
# 返回Selenium 浏览器的参数
# print("当前浏览器内置user-agent:", driver.execute_script('return navigator.userAgent'))
# print("当前浏览器内置user-agent-plugins:", driver.execute_script('return navigator.plugins.length'))
# print("当前浏览器内置user-agent-languages:", driver.execute_script('return navigator.languages'))
time.sleep(3)
# page_source 是渲染后的页面源代码,类型为字符串,包含了想要的数据
page_source = driver.page_source
driver.close()
# 为了便于对照,根据拿到 page_source 的时间,先保留1份原始文本,
response_time = time.strftime("%Y%m%d%H%M%S")
with open("{}_{}_{}_original.html".format(city, month, response_time), 'w', encoding='utf-8') as f:
f.write(page_source)
主角上阵
现在渲染前、后的网页源代码我们都已拿到,让我们告别龙套 Selenium,该是主角 正则表达式 大显身手的时候了。
前言中提到匹配是关键,其实匹配也有前提,就是要找到规律。好在这个案例中假数据规律都比较明显,我们一个个来看。
真table vs 假table
严格来讲,没有全部是假数据的 假table,也没有全部是真数据的 真table。对,他就是这么神奇和牛逼 。在所谓的“假Table” 中,也能找到和“真Table”一致的数据 —— 你可以打开浏览器访问页面,然后和源代码逐行逐列逐单元格进行数据比对,虽然很费功夫,但这确实是事实,你需要接受。
另1个非常明显的佐证是实现页面渲染的 js 代码,在这个名为 showTable 的函数中,入参 items是ajax 接口返回的 json 格式数据,通过 items.foreach 遍历,对3个 Table(3个不同 id)渲染。在每个Table的 td 标签中,都有包含了 假的Math.random() 和 真的item.天气字段 数据。而且出现的位置随机,字段随机。
假数据肯定是不会在页面展示的,他只是反爬措施的一部分。换句话说,用来迷惑或者拦截掉那些水平一般的爬虫 。我们当然可以找到控制展示的逻辑,然后逐个 td 匹配进而替换,但毫无疑问这样效率极低,没有必要直接在最小范围操作。即便这样做了,那些所谓“假Table”中剩下的真数据,怎么处理?—— 最终还是要回到 Table 范畴。
既然是这样,我们就直接在 Table 层面来找不同 —— 找到“真Table”,剔除“假Table”。
首先你会发现id 不同,但这个 id 是每次请求后都会变化的随机字符串,不能作为比较的凭证。
其次是class引用样式的名称不同,但他和 id 一样,也是随机变化的,即便他们对应的内容都是 display:none
所以接下来,我们就找到内容固定的 style 部分,能看出来2个 Table 包含了对 position 属性的设置,而另1个没有。没有设置的这颗独苗,你可以在再和页面做一遍数据比对,虽然多了些页面没展示的,但是页面展示的数据都在这里。对的,这就是我们的目标。
让我们请出这个前不见古人后不见来者的正则表达式。这里有2行额外的代码,用来将源代码中的 eval 部分(会转换为js 代码,可以看我的 js 逆向文章)替换为空,因为这部分内容太长了,长到令人发指,会严重影响后续匹配的效率和时间。
# 可以先移除Script 中的eval,否则太长了,移除后 size 会减少很多
# 正则匹配也是运算,应该尽可能减小匹配范围
regex_script = r"eval\(.*"
page_source = re.sub(regex_script, '', page_source)
# 调试需要,用于统计程序运行时间
s1_time_start = time.time()
# 样式中没有设置 position 的Table,就是包含真实数据的,保留。将另外2个 替换为空
# 一步到位的正则表达式
re_one_step = r"(?=)[\s\S])*?position[\s\S]*?(?<=<\/table>)"
page_source, count = re.subn(re_one_step, '', page_source)
print('{}_{}: {} fake tables have been removed within {}s'.format(city, month, count,time.time() - s1_time_start)))
# 调试需要,我们再保存1份剩下了 “真Table”的网页源代码
with open("{}_{}_{}_removefaketable.html".format(city, month, response_time), 'w', encoding='utf-8') as f:
f.write(page_source)
另外使用了 re.subn 函数而不是常见的 re.sub,re.subn 会返回1个元组,其中第1个元素是替换后的字符串,第2个元素是替换次数。便于我们观察调试信息。即使这里毫无疑问地只有2个Table会被替换。
真td vs 假td
现在我们拿到了包含真实数据的Table。重申:他只是包含,并不是全部,这很重要 。我们来看 2015-01-01 的数据,页面上在这行展示了9个数据,而Table 的 tr 中提供了19个 td,也就是19个数据。
19个数据,我们没有办法通过数字本身去识别真伪,对于爬虫来讲他们毫无意义。只有那些人类可读的 hidden 样式,以及那些很明显是随机字符串的样式名称,在默默诉说着什么。以页面上没有展示数字20和70为例,当你按下 Ctrl 同时点击那些随机字符串,会发现他们对应的真实样式,全部是 display:none。好了,电影《寒战》经典台词:“rule number 1” —— 用来剔除伪数据的第1条样式出炉。
但从19个甚至更多数据得到9个有效数据,rule number 1 还远远不够。我们还找到了剩下的3个 rule:
rule number 2: 直接就是 display:none
rule number 3: hidden-lg —— 这个很特别 lg 是大型设备上隐藏,参考阅读:Bootstrap 响应式实用工具
rule number 4: 直接就是 hidden
rule number 5: 没有了,hidden-xs 不是,hidden-sm 和 hidden-md 也不是 —— 就是这么牛逼,hidden 也区分不同的适用对象
正则表达式,请继续你的表演。
第1步,得到全部td。对于1份正常——纯真没有无邪的数据来说,td 数量应该是9的倍数 —— 因为页面上就展示9个字段,再结合天数,假设每天都有数据,那 td 不外乎288(31天 + 1表头),279(30天 + 1表头),161(28天 + 1表头)——即便不是每天都有数据,td 数量等于9的倍数这个铁律是没跑的。但实际在不同请求当中,因为随机伪数据的存在,得到的td 数量都是随机的。我们也把他打印出来。
第2步,在全部td 中,对前面得到的4种样式排名不分先后进行逐个匹配,匹配到就意味着属于将要被隐藏的数据,直接将这个td 替换为空。需要注意的是,对于名称是随机字符串的样式 —— rule number 1 来说,是先在源代码全文中匹配用{} 包含的display:none,然后提取出 { 前面的这个字符串,平均数量10个左右,你会得到1个列表,再然后在 td 中匹配这些字符串并替换 —— 这和 rule number 2 直接将 display:none 明文写在td样式中的处理逻辑不同。
第3步,可选,为了和第1步的结论呼应,我们再匹配1次td,得到td 的数量,以确认我们的处理逻辑是正确的。
# 在保留的 table 中匹配出所有的 td
regex_td = r""
tds = re.findall(regex_td, page_source)
print('{}_{}: total {} tds been found'.format(city, month, len(tds)))
# 对假数据的隐藏,网站使用了4种不同的css样式来控制,目前就找到4种。将包含这4种样式的 td 全部替换为空
# 第1种 直接就是display:none
# 第2种 使用了样式别名,名称是随机字符串,但内容固定是 display:none,需要通过内容反向拿到样式别名
# 第3种 hidden-lg - 这个很特别 lg 是大型设备上隐藏
# 第4种 hidden
regex_td_css1 = r"display:none"
for td in tds:
if re.findall(regex_td_css1, td):
page_source = page_source.replace(td, '')
# 将包含 display:none 隐藏样式的 td 其实就是假数据,替换为空
# display:none 是最终效果,实际在代码里是随机字符串,而且好几个,所以先找到 css 定义中内容为 display:none 的样式名称
regex_td_css2 = r"(.*?)\s*{\n\s*display: none;"
class_ndisplays = re.findall(regex_td_css2, page_source)
# print('class_ndisplays', len(class_ndisplays))
# 将包含这些样式的 td 替换为空
for class_ndisplay in class_ndisplays:
class_ndisplay = class_ndisplay.replace('.', '').strip()
for td in tds:
if re.findall(class_ndisplay, td):
page_source = page_source.replace(td, '')
# 将包含 hidden-lg 隐藏样式的 td 其实就是假数据,替换为空
regex_td_css3 = "hidden-lg"
for td in tds:
if re.findall(regex_td_css3, td):
page_source = page_source.replace(td, '')
# 将包含 hidden 隐藏样式的 td 其实就是假数据,替换为空
regex_td_css4 = r"\"hidden\""
for td in tds:
if re.findall(regex_td_css4, td):
page_source = page_source.replace(td, '')
# 可选,再次匹配,现在得到的是包含真实数据的 td
# 经过前面的处理,得到的有效td 数量应该固定为 (天数 + 表头)* 9列
# (31 + 1)*9 = 288 或者 (30+1)*9 = 279
regex_td = r""
tds_real = re.findall(regex_td, page_source)
print('{}_{}: {} tds which contain real data been left'.format(city, month, len(tds_real)))
终于!!!彻底!!!我们拿到了只剩真实数字(注意是数字!卖个关子,你还会继续发现惊喜和意外。哈哈哈哈哈 )的网页源代码!!!每一个 tr 都只有9条 td,可以再来和页面做个比对,数字完全一致。9真是这个案例的吉祥数字。细心的同学会发现两边数字的次序不同,对,因为图左是浏览器请求,图右是Python 代码请求。没错,每次请求拿到的数据顺序也是变化的。
到这里,我们把这个经过 Scrapy middleware 处理的网页源代码封装后发给 Scrapy Spider,在Spider 中做最后的数据提取。这里的提取我们用了 xpath
第1步,从页面中找出全部 tr,数量最多32个。
第2步,需要先从第1个 tr (也就是表头)中提取天气指标字段保存成列表,因为顺序不固定,所以每次都要提取,好让剩下的 tr 中的数字逐个对应到指标,这样最终的数据才有意义。因为只有1个 tr 需要这样处理,所以放在了 else 逻辑中,而用if 来处理绝大多数的 tr。
第3步,也就是 if 逻辑中,逐个提取数据,用指标列表作为key,提取到的数字作为 value,保存进字典 item.
其他一些额外的逻辑就是对表头的字符串处理,为了让不同的爬虫能套用同1套item 定义
def parse_month(self, response):
# 这里拿到的 response,应该是已经剔除掉全部伪数据的(包括表头伪数据)
# print(response.meta)
city = response.meta['city']
month = response.meta['month']
item = S007AqiItem()
# xpath 得到 tr,每个页面上 tr 最多32个 (31天 + 1表头)
trows = response.xpath('//tr')
print('{}_{}: {} rows been found'.format(city, month, len(trows)))
# 定义1个列表,用于储存表头字段
theaders_original = []
theaders_purified = []
# 循环,提取每个 tr 下的 td 中的数据
for trow, trow_count in zip(trows, list(range(0, len(trows)))):
# 每个 tr 里面包含 9个 td
tdatas = trow.xpath('./td')
# 提取剩余的31行
if trow_count != 0:
tdata_count = 0
for tdata in tdatas:
data = tdata.xpath('./text()').extract_first()
item['{}'.format(theaders_purified[tdata_count])] = data
tdata_count = tdata_count + 1
item['city'] = city
item['month'] = month
print(item)
# 第1个 tr 里面是表头,单独提取
else:
for tdata in tdatas:
field_name = tdata.xpath('./text()').extract_first()
theaders_original.append(field_name)
# 表头名称转换,变成英文小写,这样可以和使用ajax 方式的爬虫共用1个 item
if field_name == "日期": field_name = 'day'
elif field_name == "质量等级": field_name = 'quality'
elif field_name == "O3_8h": field_name = 'o3'
elif field_name == "PM2.5":field_name = 'pm2_5'
else: field_name = field_name.lower()
# 空列表不能直接使用数字索引赋值
theaders_purified.append(field_name)
print('{}_{}: original table headers : {}'.format(city, month, theaders_original))
print('{}_{}: purified table headers : {}'.format(city, month, theaders_purified))
真th vs 假th
前面红色字体处卖了个关子,拿到真实数字并不意味着万事大吉。为什么强调数字?—— 因为还有例外,就是表头。对,大部分情况下,表头也是写在 td 里的,这样只需要1套处理 td 的逻辑。但是哈但是,哈哈哈哈哈哈,你还会遇到表头写在 th 中的情况 —— 我没找着规律,似乎是在连续快速请求的情况下会出现。
为了让我们的爬虫更健壮,我们把这种情况也纳入考量。找到 th 是第1步,之后可以考虑在 th 中匹配 css rule 1-4,把假 th 剔除,但想想就闹心,难不成又来4次 for 循环? 所以换个思路,我们把所有的 th 替换为 td,放在td 处理逻辑前面,这样后续只处理 td 就好了。哈哈哈哈哈,你有张良计我有过墙梯。
# 表头也是包含了伪造数据的,也需要剔除 表头通过2种形式提供,
# 一种是放在 td 里的,可以和数据一起处理
# 另一种是放在 th 里,所以还需要增加 th 的匹配判断
# 保留下来的 Table 中, td 是一定有的,th 不一定有
# 最简单的方式就是把 th 替换为 td,这样就不用在 th 里依次判断4种隐藏样式
regex_th = r""
# 无论最终是否执行替换,正则匹配都会执行。所以把 re.findall 换成 re.subn
# 正则匹配后得到match,如果其中有闭合的(),就会生成 group,也就是分组
# 正则将之间的内容匹配出来,得到分组,用\1表示
# 将匹配到的分组内容保留,两端替换为td的开合标签
page_source, count = re.subn(regex_th, r"", page_source)
if count > 0:
print('{}_{}: field names are inside of , rather than . {} ths been replaced.'.format(city, month, count))
另类的 span
做完了前面的全部,你会发现结果里少了点什么,对,表头拿到了,数字拿到了,但是质量等级这个指标没有被提取出来 —— 为什么?回去看网页源代码,会发现质量等级是在 td 标签内部又嵌套了一层的 span 标签里。那好办,我们for 循环所有td,在td 里先找着 span 标签,然后提取其中的文本,用文本把这整个span 替换,这样把质量等级字段也处理成和其他字段一致的形式。
# 质量等级 是在 td 内部又包了1层 span 标签,为了和其他数据统一逻辑,我们把span 内的文本提取出来
# 然后用这个文本 把整个 span 标签替换掉
regex_span = r"" # 结果要包含开头的
regex_span_text = r"(?<=>).+(?=<)" # 结果不要包含开头的 < 和 结尾的 >, 只取<> 之间的内容
for td in tds:
span_tag = re.findall(regex_span, td)
if span_tag:
span_text = re.findall(regex_span_text, span_tag[0])[0]
page_source = page_source.replace(span_tag[0], span_text)
############################华丽丽的分割线##########################################
# 上面这个是最开始的写法,看上去就非常臃肿
# 下面这个是改良写法,看上去就非常牛逼
# 效果是把 质量等级
# 一步到位替换成了 质量等级
# \3 是因为质量等级在正则匹配结果的第3个分组
regex_span = r"(?=)[\s\S])*((.*?)<\/span>)<\/td>"
page_source, count = re.subn(regex_span , r' \3 ', page_source)
到这里,目前所有的意外都被我们处理掉了,数据 —— 所有的美好如期而至。无图无真相,来看个视频吧。视频被压缩得太厉害了,将就看吧。
结语
上面放的那个视频,我做了剪辑,中间砍掉了大概50s的样子。从这里也能看出 Selenium 方案的天然劣势:慢。除了 Selenium 自身之外,文本处理耗费了相当长的时间,有这功夫,js逆向 + ajax 请求方案至少爬10个页面吧。但这不失为1种可行方案 —— 在熟悉和熟练掌握正则表达式的前提下。
Todo
在现在这个基础上,还能想到的几个时长优化思路:
第1:4个隐藏样式匹配那里,对全部td做了4次循环,而且是用了 re.findall 然后 replace。撇开 rule number 1 需要逆向找到字符串再处理外,其他3个rule 其实可以考虑使用 re.subn(regex_rule2 | regex_rule3 | regex_rule4 , '', td) —— 1次性匹配3个正则其中1个,同时替换,这样可以减少2次 for 循环,而且代码简洁度大大提升。
第2:简化 span 的处理逻辑,新的代码已经放上去了,7行代码精简成了2行,但是正则表达式更牛逼 —— 复杂了。
这2个思路共通的地方是 将 re.findall + for 循环 + replace ,替换为 re.sub。 区别在于前面这个方案是不断缩小范围,后面这个是直接在大范围内(其实也可以改小)。总的来说是 replace 可以被干掉。但是实际性能和效率对比如何,待进一步考证吧。
你可能感兴趣的:(python,python,爬虫,selenium)
python 读excel每行替换_Python脚本操作Excel实现批量替换功能
weixin_39646695
python 读excel每行替换
Python脚本操作Excel实现批量替换功能大家好,给大家分享下如何使用Python脚本操作Excel实现批量替换。使用的工具Openpyxl,一个处理excel的python库,处理excel,其实针对的就是WorkBook,Sheet,Cell这三个最根本的元素~明确需求原始excel如下我们的目标是把下面excel工作表的sheet1表页A列的内容“替换我吧”批量替换为B列的“我用来替换的
Selenium 特殊控件操作与 ActionChains 实践详解
小馋喵知识杂货铺
selenium 测试工具
1.下拉框单选操作(a)使用SeleniumSelect类(标准HTML标签)Selenium提供了内置的Select类用于操作标准下拉框,这种方式简单且直观。fromselenium.webdriver.support.uiimportSelect#定位下拉框dropdown=Select(driver.find_element("id","dropdown_id"))#通过以下三种方式选择单个
python笔记14介绍几个魔法方法
抢公主的大魔王
python python
python笔记14介绍几个魔法方法先声明一下各位大佬,这是我的笔记。如有错误,恳请指正。另外,感谢您的观看,谢谢啦!(1).__doc__输出对应的函数,类的说明文档print(print.__doc__)print(value,...,sep='',end='\n',file=sys.stdout,flush=False)Printsthevaluestoastream,ortosys.std
selenium特殊场景处理
Monica_ll
Selenium selenium chrome python
文章目录前言一、多窗口处理二、浏览器弹窗处理包含alert、confirm、prompt三、鼠标和键盘事件处理前言在使用selenium操作浏览器的过程中可能需要借助键盘和鼠标功能完成一些操作,或者操作弹窗处理,本文主要是整理自己工作过程中使用过的一些方法一、多窗口处理在实际测试过程中经常会有通过点击或者连接打开新的窗口,这种情况下就需要切换webDriver到对应浏览器对象才能操作新窗口的元素。
Anaconda 和 Miniconda:功能详解与选择建议
古月฿
python入门 python conda
Anaconda和Miniconda详细介绍一、Anaconda的详细介绍1.什么是Anaconda?Anaconda是一个开源的包管理和环境管理工具,在数据科学、机器学习以及科学计算领域发挥着关键作用。它以Python和R语言为基础,为用户精心准备了大量预装库和工具,极大地缩短了搭建数据科学环境的时间。对于那些想要快速开展数据分析、模型训练等工作的人员来说,Anaconda就像是一个一站式的“数
环境搭建 | Python + Anaconda / Miniconda + PyCharm 的安装、配置与使用
本文将分别介绍Python、Anaconda/Miniconda、PyCharm的安装、配置与使用,详细介绍Python环境搭建的全过程,涵盖Python、Pip、PythonLauncher、Anaconda、Miniconda、Pycharm等内容,以官方文档为参照,使用经验为补充,内容全面而详实。由于图片太多,就先贴一个无图简化版吧,详情请查看Python+Anaconda/Minicond
你竟然还在用克隆删除?Conda最新版rename命令全攻略!
曦紫沐
Python基础知识 conda 虚拟环境管理
文章摘要Conda虚拟环境管理终于迎来革命性升级!本文揭秘Conda4.9+版本新增的rename黑科技,彻底告别传统“克隆+删除”的繁琐操作。从命令解析到实战案例,手把手教你如何安全高效地重命名Python虚拟环境,附带版本检测、环境迁移、故障排查等进阶技巧,助你提升开发效率10倍!一、颠覆认知:Conda居然自带重命名功能?很多开发者仍停留在“Conda无法直接重命名环境”的认知阶段,实际上自
centos7安装配置 Anaconda3
Anaconda是一个用于科学计算的Python发行版,Anaconda于Python,相当于centos于linux。下载[root@testsrc]#mwgethttps://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.2.0-Linux-x86_64.shBegintodownload:Anaconda3-5.2.0-L
Pandas:数据科学的超级瑞士军刀
科技林总
DeepSeek学AI 人工智能
**——从零基础到高效分析的进化指南**###**一、Pandas诞生:数据革命的救世主****2010年前的数据分析噩梦**:```python#传统Python处理表格数据data=[]forrowincsv_file:ifrow[3]>100androw[2]=="China":data.append(float(row[5])#代码冗长易错!```**核心痛点**:-Excel处理百万行崩
Selenium基础教程
lemontree1945
selenium python 测试工具
1.Selenium环境安装1.1浏览器安装Chrome和ChromeDriver下载地址:https://googlechromelabs.github.io/chrome-for-testing/注意:驱动版本号要和浏览器版本号一致;安装后关闭浏览器自动更新:services.msc:打开系统服务找到和google相关的服务,全部修改为禁用1.2安装第三方库seleniumpipinstall
【Jupyter】个人开发常见命令
TIM老师
# Pycharm & VSCode python Jupyter
1.查看python版本importsysprint(sys.version)2.ipynb/py文件转换jupyternbconvert--topythonmy_file.ipynbipynb转换为mdjupyternbconvert--tomdmy_file.ipynbipynb转为htmljupyternbconvert--tohtmlmy_file.ipynbipython转换为pdfju
用 Python 开发小游戏:零基础也能做出《贪吃蛇》
本文专为零基础学习者打造,详细介绍如何用Python开发经典小游戏《贪吃蛇》。无需复杂编程知识,从环境搭建到代码编写、功能实现,逐步讲解核心逻辑与操作。涵盖Pygame库的基础运用、游戏界面设计、蛇的移动与食物生成规则等,让新手能按步骤完成开发,同时融入SEO优化要点,帮助读者轻松入门Python游戏开发,体验从0到1做出游戏的乐趣。一、为什么选择用Python开发《贪吃蛇》对于零基础学习者来说,
基于Python的AI健康助手:开发与部署全攻略
AI算力网络与通信
AI算力网络与通信原理 AI人工智能大数据架构 python 人工智能 开发语言 ai
基于Python的AI健康助手:开发与部署全攻略关键词:Python、AI健康助手、机器学习、自然语言处理、Flask、部署、健康管理摘要:本文将详细介绍如何使用Python开发一个AI健康助手,从需求分析、技术选型到核心功能实现,再到最终部署上线的完整过程。我们将使用自然语言处理技术理解用户健康咨询,通过机器学习模型提供个性化建议,并展示如何用Flask框架构建Web应用接口。文章包含大量实际代
AI人工智能中的数据挖掘:提升智能决策能力
AI人工智能中的数据挖掘:提升智能决策能力关键词:数据挖掘、人工智能、机器学习、智能决策、数据分析、特征工程、模型优化摘要:本文深入探讨了数据挖掘在人工智能领域中的核心作用,重点分析了如何通过数据挖掘技术提升智能决策能力。文章从基础概念出发,详细介绍了数据挖掘的关键算法、数学模型和实际应用场景,并通过Python代码示例展示了数据挖掘的全流程。最后,文章展望了数据挖掘技术的未来发展趋势和面临的挑战
lesson20:Python函数的标注
你的电影很有趣
python 开发语言
目录引言:为什么函数标注是现代Python开发的必备技能一、函数标注的基础语法1.1参数与返回值标注1.2支持的标注类型1.3Python3.9+的重大改进:标准集合泛型二、高级标注技巧与最佳实践2.1复杂参数结构标注2.2函数类型与回调标注2.3变量注解与类型别名三、静态类型检查工具应用3.1mypy:最流行的类型检查器3.2Pyright与IDE集成3.3运行时类型验证四、函数标注的工程价值与
Jupyter Notebook:数据科学的“瑞士军刀”
a小胡哦
机器学习基础 人工智能 机器学习
在数据科学的世界里,JupyterNotebook是一个不可或缺的工具,它就像是数据科学家手中的“瑞士军刀”,功能强大且灵活多变。今天,就让我们一起深入了解这个神奇的工具。一、JupyterNotebook是什么?JupyterNotebook是一个开源的Web应用程序,它允许你创建和共享包含实时代码、方程、可视化和解释性文本的文档。它支持多种编程语言,其中Python是最常用的语言之一。Jupy
selenium 特殊场景处理
文章目录前言一、windows的弹窗二、内嵌网页frame三、页签切换四、截图五、弹窗六、JS执行总结前言selenium处理web操作师,有很多特殊的情况需要处理,例如弹窗、内嵌网页,页签切换,js执行等,下面介绍一些可能会遇到的特殊场景一、windows的弹窗importwin32com.client'''创建了一个WScript.ShellCOM(ComponentObjectModel)对
Django学习笔记(一)
学习视频为:pythondjangoweb框架开发入门全套视频教程一、安装pipinstalldjango==****检查是否安装成功django.get_version()二、django新建项目操作1、新建一个项目django-adminstartprojectproject_name2、新建APPcdproject_namedjango-adminstartappApp注:一个project
Python 程序设计讲义(26):字符串的用法——字符的编码
睿思达DBA_WGX
Python 讲义 python 开发语言
Python程序设计讲义(26):字符串的用法——字符的编码目录Python程序设计讲义(26):字符串的用法——字符的编码一、字符的编码二、`ASCII`编码三、`Unicode`编码四、使用`ord()`函数查询一个字符对应的`Unicode`编码五、使用`chr()`函数查询一个`Unicode`编码对应的字符六、`Python`字符串的特征一、字符的编码计算机默认只能处理二进制数,而不能处
【Python】pypinyin-汉字拼音转换工具
鸟哥大大
Python python 自然语言处理
文章目录1.主要功能2.安装3.常用API3.1拼音风格3.2核心API3.2.1pypinyin.pinyin()3.2.2pypinyin.lazy_pinyin()3.2.3pypinyin.load_single_dict()3.2.4pypinyin.load_phrases_dict()3.2.5pypinyin.slug()3.3注册新的拼音风格4.基本用法4.1库导入4.2基本汉字
python编程第十四课:数据可视化
小小源助手
Python代码实例 信息可视化 python 开发语言
Python数据可视化:让数据“开口说话”在当今数据爆炸的时代,数据可视化已成为探索数据规律、传达数据信息的关键技术。Python凭借其丰富的第三方库,为数据可视化提供了强大而灵活的解决方案。本文将带你深入了解Matplotlib库的基础绘图、Seaborn库的高级可视化以及交互式可视化工具Plotly,帮助你通过图表清晰地展示数据背后的故事。一、Matplotlib库基础绘图Matplotlib
Python数据可视化:用代码绘制数据背后的故事
AAEllisonPang
Python 信息可视化 python 开发语言
引言:当数据会说话在数据爆炸的时代,可视化是解锁数据价值的金钥匙。Python凭借其丰富的可视化生态库,已成为数据科学家的首选工具。本文将带您从基础到高级,探索如何用Python将冰冷数字转化为引人入胜的视觉叙事。一、基础篇:二维可视化的艺术表达1.1Matplotlib:可视化领域的瑞士军刀importmatplotlib.pyplotaspltimportnumpyasnpx=np.linsp
python学习笔记(汇总)
朕的剑还未配妥
python学习笔记整理 python 学习 开发语言
文章目录一.基础知识二.python中的数据类型三.运算符四.程序的控制结构五.列表六.字典七.元组八.集合九.字符串十.函数十一.解决bug一.基础知识print函数字符串要加引号,数字可不加引号,如print(123.4)print('小谢')print("洛天依")还可输入表达式,如print(1+3)如果使用三引号,print打印的内容可不在同一行print("line1line2line
Gerapy爬虫管理框架深度解析:企业级分布式爬虫管控平台
Python×CATIA工业智造
爬虫 分布式 python pycharm
引言:爬虫工程化的必然选择随着企业数据采集需求指数级增长,传统单点爬虫管理模式面临三重困境:管理效率瓶颈:手动部署耗时占开发总时长的40%以上系统可靠性低:研究显示超过65%的爬虫故障源于部署或调度错误资源利用率差:平均爬虫服务器CPU利用率不足30%爬虫管理方案对比:┌───────────────┬─────────────┬───────────┬───────────┬──────────
PDF转Markdown - Python 实现方案与代码
Eiceblue
Python Python PDF pdf python 开发语言 vscode
PDF作为广泛使用的文档格式,转换为轻量级标记语言Markdown后,可无缝集成到技术文档、博客平台和版本控制系统中,提高内容的可编辑性和可访问性。本文将详细介绍如何使用国产Spire.PDFforPython库将PDF文档转换为Markdown格式。技术优势:精准保留原始文档结构(段落/列表/表格)完整提取文本和图像内容无需Adobe依赖的纯Python实现支持Linux/Windows/mac
使用Python和Gradio构建实时数据可视化工具
PythonAI编程架构实战家
信息可视化 python 开发语言 ai
使用Python和Gradio构建实时数据可视化工具关键词:Python、Gradio、数据可视化、实时数据、Web应用、交互式界面、数据科学摘要:本文将详细介绍如何使用Python和Gradio框架构建一个实时数据可视化工具。我们将从基础概念开始,逐步深入到核心算法实现,包括数据处理、可视化技术以及Gradio的交互式界面设计。通过实际项目案例,读者将学习如何创建一个功能完整、响应迅速的实时数据
Python Gradio:实现交互式图像编辑
PythonAI编程架构实战家
Python编程之道 python 开发语言 ai
PythonGradio:实现交互式图像编辑关键词:Python,Gradio,交互式图像编辑,计算机视觉,深度学习,图像处理,Web应用摘要:本文将深入探讨如何使用Python的Gradio库构建交互式图像编辑应用。我们将从基础概念开始,逐步介绍Gradio的核心功能,并通过实际代码示例展示如何实现各种图像处理功能。文章将涵盖图像滤镜应用、对象检测、风格迁移等高级功能,同时提供完整的项目实战案例
数据可视化:数据世界的直观呈现
卢政权1
信息可视化 数据分析 数据挖掘
在当今数字化浪潮中,数据呈爆炸式增长。数据可视化作为一种强大的技术手段,能够将复杂的数据转化为直观的图形、图表等形式,让数据背后的信息一目了然。无论是在商业决策、科学研究还是日常数据分析中,数据可视化都发挥着极为重要的作用。它帮助我们快速理解数据的分布、趋势、关联等特征,从而为进一步的分析和行动提供有力支持。接下来,我们将深入探讨数据可视化的奥秘,并通过代码示例展示其实际应用。一、Python数据
Python 程序设计讲义(25):循环结构——嵌套循环
Python程序设计讲义(25):循环结构——嵌套循环目录Python程序设计讲义(25):循环结构——嵌套循环一、嵌套循环的执行流程二、嵌套循环对应的几种情况1、内循环和外循环互不影响2、外循环迭代影响内循环的条件3、外循环迭代影响内循环的循环体嵌套循环是指在一个循环体中嵌套另一个循环。while循环中可以嵌入另一个while循环或for循环。反之,也可以在for循环中嵌入另一个for循环或wh
基于Python引擎的PP-OCR模型库推理
张欣-男
python ocr 开发语言 PaddleOCR PaddlePaddle
基于Python引擎的PP-OCR模型库推理1.文本检测模型推理#下载超轻量中文检测模型:wgethttps://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tartarxfch_PP-OCRv3_det_infer.tarpython3tools/infer/predict_det.py--image_dir=".
[星球大战]阿纳金的背叛
comsci
本来杰迪圣殿的长老是不同意让阿纳金接受训练的.........
但是由于政治原因,长老会妥协了...这给邪恶的力量带来了机会
所以......现代的地球联邦接受了这个教训...绝对不让某些年轻人进入学院
看懂它,你就可以任性的玩耍了!
aijuans
JavaScript
javascript作为前端开发的标配技能,如果不掌握好它的三大特点:1.原型 2.作用域 3. 闭包 ,又怎么可以说你学好了这门语言呢?如果标配的技能都没有撑握好,怎么可以任性的玩耍呢?怎么验证自己学好了以上三个基本点呢,我找到一段不错的代码,稍加改动,如果能够读懂它,那么你就可以任性了。
function jClass(b
Java常用工具包 Jodd
Kai_Ge
java jodd
Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架。简单,却很强大! 写道 Jodd = Tools + IoC + MVC + DB + AOP + TX + JSON + HTML < 1.5 Mb
Jodd 被分成众多模块,按需选择,其中
工具类模块有:
jodd-core &nb
SpringMvc下载
120153216
springMVC
@RequestMapping(value = WebUrlConstant.DOWNLOAD)
public void download(HttpServletRequest request,HttpServletResponse response,String fileName) {
OutputStream os = null;
InputStream is = null;
Python 标准异常总结
2002wmj
python
Python标准异常总结
AssertionError 断言语句(assert)失败 AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d) FloatingPointError 浮点计算错误 GeneratorExit generator.close()方法被调用的时候 ImportError 导入模块失
SQL函数返回临时表结构的数据用于查询
357029540
SQL Server
这两天在做一个查询的SQL,这个SQL的一个条件是通过游标实现另外两张表查询出一个多条数据,这些数据都是INT类型,然后用IN条件进行查询,并且查询这两张表需要通过外部传入参数才能查询出所需数据,于是想到了用SQL函数返回值,并且也这样做了,由于是返回多条数据,所以把查询出来的INT类型值都拼接为了字符串,这时就遇到问题了,在查询SQL中因为条件是INT值,SQL函数的CAST和CONVERST都
java 时间格式化 | 比较大小| 时区 个人笔记
7454103
java eclipse tomcat c MyEclipse
个人总结! 不当之处多多包含!
引用 1.0 如何设置 tomcat 的时区:
位置:(catalina.bat---JAVA_OPTS 下面加上)
set JAVA_OPT
时间获取Clander的用法
adminjun
Clander 时间
/**
* 得到几天前的时间
* @param d
* @param day
* @return
*/
public static Date getDateBefore(Date d,int day){
Calend
JVM初探与设置
aijuans
java
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台
SQL中ON和WHERE的区别
avords
SQL中ON和WHERE的区别
数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。 www.2cto.com 在使用left jion时,on和where条件的区别如下: 1、 on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
说说自信
houxinyou
工作 生活
自信的来源分为两种,一种是源于实力,一种源于头脑.实力是一个综合的评定,有自身的能力,能利用的资源等.比如我想去月亮上,要身体素质过硬,还要有飞船等等一系列的东西.这些都属于实力的一部分.而头脑不同,只要你头脑够简单就可以了!同样要上月亮上,你想,我一跳,1米,我多跳几下,跳个几年,应该就到了!什么?你说我会往下掉?你笨呀你!找个东西踩一下不就行了吗?
无论工作还
WEBLOGIC事务超时设置
bijian1013
weblogic jta 事务超时
系统中统计数据,由于调用统计过程,执行时间超过了weblogic设置的时间,提示如下错误:
统计数据出错!
原因:The transaction is no longer active - status: 'Rolling Back. [Reason=weblogic.transaction.internal
两年已过去,再看该如何快速融入新团队
bingyingao
java 互联网 融入 架构 新团队
偶得的空闲,翻到了两年前的帖子
该如何快速融入一个新团队,有所感触,就记下来,为下一个两年后的今天做参考。
时隔两年半之后的今天,再来看当初的这个博客,别有一番滋味。而我已经于今年三月份离开了当初所在的团队,加入另外的一个项目组,2011年的这篇博客之后的时光,我很好的融入了那个团队,而直到现在和同事们关系都特别好。大家在短短一年半的时间离一起经历了一
【Spark七十七】Spark分析Nginx和Apache的access.log
bit1129
apache
Spark分析Nginx和Apache的access.log,第一个问题是要对Nginx和Apache的access.log文件进行按行解析,按行解析就的方法是正则表达式:
Nginx的access.log解析正则表达式
val PATTERN = """([^ ]*) ([^ ]*) ([^ ]*) (\\[.*\\]) (\&q
Erlang patch
bookjovi
erlang
Totally five patchs committed to erlang otp, just small patchs.
IMO, erlang really is a interesting programming language, I really like its concurrency feature.
but the functional programming style
log4j日志路径中加入日期
bro_feng
java log4j
要用log4j使用记录日志,日志路径有每日的日期,文件大小5M新增文件。
实现方式
log4j:
<appender name="serviceLog"
class="org.apache.log4j.RollingFileAppender">
<param name="Encoding" v
读《研磨设计模式》-代码笔记-桥接模式
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
/**
* 个人觉得关于桥接模式的例子,蜡笔和毛笔这个例子是最贴切的:http://www.cnblogs.com/zhenyulu/articles/67016.html
* 笔和颜色是可分离的,蜡笔把两者耦合在一起了:一支蜡笔只有一种
windows7下SVN和Eclipse插件安装
chenyu19891124
eclipse插件
今天花了一天时间弄SVN和Eclipse插件的安装,今天弄好了。svn插件和Eclipse整合有两种方式,一种是直接下载插件包,二种是通过Eclipse在线更新。由于之前Eclipse版本和svn插件版本有差别,始终是没装上。最后在网上找到了适合的版本。所用的环境系统:windows7JDK:1.7svn插件包版本:1.8.16Eclipse:3.7.2工具下载地址:Eclipse下在地址:htt
[转帖]工作流引擎设计思路
comsci
设计模式 工作 应用服务器 workflow 企业应用
作为国内的同行,我非常希望在流程设计方面和大家交流,刚发现篇好文(那么好的文章,现在才发现,可惜),关于流程设计的一些原理,个人觉得本文站得高,看得远,比俺的文章有深度,转载如下
=================================================================================
自开博以来不断有朋友来探讨工作流引擎该如何
Linux 查看内存,CPU及硬盘大小的方法
daizj
linux cpu 内存 硬盘 大小
一、查看CPU信息的命令
[root@R4 ~]# cat /proc/cpuinfo |grep "model name" && cat /proc/cpuinfo |grep "physical id"
model name : Intel(R) Xeon(R) CPU X5450 @ 3.00GHz
model name :
linux 踢出在线用户
dongwei_6688
linux
两个步骤:
1.用w命令找到要踢出的用户,比如下面:
[root@localhost ~]# w
18:16:55 up 39 days, 8:27, 3 users, load average: 0.03, 0.03, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
放手吧,就像不曾拥有过一样
dcj3sjt126com
内容提要:
静悠悠编著的《放手吧就像不曾拥有过一样》集结“全球华语世界最舒缓心灵”的精华故事,触碰生命最深层次的感动,献给全世界亿万读者。《放手吧就像不曾拥有过一样》的作者衷心地祝愿每一位读者都给自己一个重新出发的理由,将那些令你痛苦的、扛起的、背负的,一并都放下吧!把憔悴的面容换做一种清淡的微笑,把沉重的步伐调节成春天五线谱上的音符,让自己踏着轻快的节奏,在人生的海面上悠然漂荡,享受宁静与
php二进制安全的含义
dcj3sjt126com
PHP
PHP里,有string的概念。
string里,每个字符的大小为byte(与PHP相比,Java的每个字符为Character,是UTF8字符,C语言的每个字符可以在编译时选择)。
byte里,有ASCII代码的字符,例如ABC,123,abc,也有一些特殊字符,例如回车,退格之类的。
特殊字符很多是不能显示的。或者说,他们的显示方式没有标准,例如编码65到哪儿都是字母A,编码97到哪儿都是字符
Linux下禁用T440s,X240的一体化触摸板(touchpad)
gashero
linux ThinkPad 触摸板
自打1月买了Thinkpad T440s就一直很火大,其中最让人恼火的莫过于触摸板。
Thinkpad的经典就包括用了小红点(TrackPoint)。但是小红点只能定位,还是需要鼠标的左右键的。但是自打T440s等开始启用了一体化触摸板,不再有实体的按键了。问题是要是好用也行。
实际使用中,触摸板一堆问题,比如定位有抖动,以及按键时会有飘逸。这就导致了单击经常就
graph_dfs
hcx2013
Graph
package edu.xidian.graph;
class MyStack {
private final int SIZE = 20;
private int[] st;
private int top;
public MyStack() {
st = new int[SIZE];
top = -1;
}
public void push(i
Spring4.1新特性——Spring核心部分及其他
jinnianshilongnian
spring 4.1
目录
Spring4.1新特性——综述
Spring4.1新特性——Spring核心部分及其他
Spring4.1新特性——Spring缓存框架增强
Spring4.1新特性——异步调用和事件机制的异常处理
Spring4.1新特性——数据库集成测试脚本初始化
Spring4.1新特性——Spring MVC增强
Spring4.1新特性——页面自动化测试框架Spring MVC T
配置HiveServer2的安全策略之自定义用户名密码验证
liyonghui160com
具体从网上看
http://doc.mapr.com/display/MapR/Using+HiveServer2#UsingHiveServer2-ConfiguringCustomAuthentication
LDAP Authentication using OpenLDAP
Setting
一位30多的程序员生涯经验总结
pda158
编程 工作 生活 咨询
1.客户在接触到产品之后,才会真正明白自己的需求。
这是我在我的第一份工作上面学来的。只有当我们给客户展示产品的时候,他们才会意识到哪些是必须的。给出一个功能性原型设计远远比一张长长的文字表格要好。 2.只要有充足的时间,所有安全防御系统都将失败。
安全防御现如今是全世界都在关注的大课题、大挑战。我们必须时时刻刻积极完善它,因为黑客只要有一次成功,就可以彻底打败你。 3.
分布式web服务架构的演变
自由的奴隶
linux Web 应用服务器 互联网
最开始,由于某些想法,于是在互联网上搭建了一个网站,这个时候甚至有可能主机都是租借的,但由于这篇文章我们只关注架构的演变历程,因此就假设这个时候已经是托管了一台主机,并且有一定的带宽了,这个时候由于网站具备了一定的特色,吸引了部分人访问,逐渐你发现系统的压力越来越高,响应速度越来越慢,而这个时候比较明显的是数据库和应用互相影响,应用出问题了,数据库也很容易出现问题,而数据库出问题的时候,应用也容易
初探Druid连接池之二——慢SQL日志记录
xingsan_zhang
日志 连接池 druid 慢SQL
由于工作原因,这里先不说连接数据库部分的配置,后面会补上,直接进入慢SQL日志记录。
1.applicationContext.xml中增加如下配置:
<bean abstract="true" id="mysql_database" class="com.alibaba.druid.pool.DruidDataSourc