python显示行数 csdn_《Python爬虫技术5天速成…》所学应用:我的项目记录 学习过程笔记21...

我的项目记录

本篇概要:

--一个函数多个返回值:

--一个需求,将几个字符串以空格连接起来形成一个字符串:

--随机休眠几秒:

--获取目标数据遇到的问题和发现:

--作死路上的感觉

--获取过程中遇到的报错1、2、应对策略

--报错3-保存字典数据到数据库:模拟的数据总在join这里报错、测试、原因、解决

--多次保存数据到excel的思路:

--作死的路上:远程主机强制关闭了一个现有的连接、解决参考

--多次保存数据到数据库时,忘记注释掉创建库函数,保存失败

--问题:excel追加的数据会覆盖掉前面已有的数据

--excel多次追加数据:不覆盖旧数据

--未解问题:不会把数据库数据导出到excel

--保存数据到数据库报错:字符串里的双引号引发的歧义、解决

--应用所学python实现想要功能后的感受

--多次保存数据到excel忘记写起始行号、忘记关闭打开的excel文档

--计算excel表行数:自动判断excel追加数据的行数起始点

20201203

14:17

--一个函数多个返回值:

def getLink(baseurl):

在这个函数里,我除了拿到视频详情页的链接,还要拿到视频的总时长,所以传回两个值:

return pagelink, videoLen

那么调用的时候,也要用两个变量来接收:

pagelink, videoLen = getLink(baseurl)

如果只用一个变量来接收的话,例如:

pagelink = getLink(baseurl)

那么pagelink这个变量接收函数返回的两个值,以列表的形式保存。一个值是一个列表,两个值就有两个列表,这两个列表又放进一个列表里。我好奇,试过打印出来看看是什么样子的,其实就是列表的嵌套,这样子的:[ [ ], [ ] ]

所以这里一定要用两个变量来接收,不然返回的值就会全部放到一个变量里。

了解了存储的格式后,虽然可以通过下标或遍历嵌套列表拿出来返回的值,但也要设变量呀,还不如一开始就直接用两个变量来接收,人家就会默认一一对应放到变量中了,方便又省事,嗯。

--一个需求,将几个字符串以空格连接起来形成一个字符串:

尝试用了加号+,没成功,后面多了一个逗号。用空格的话后面就会多一个空格,我不想要。

又尝试用列表,这个就很容易实现,一个一个追加append就行。但怎么把列表里面的元素连起来形成一个字符串呢?还是不行,不是想要的。

查看以前的笔记,字符串章节,里面有一个join(seq),看起来和我的需求匹配,去网上搜了一下用法:

(来源:Python join()方法 | 菜鸟教程 https://www.runoob.com/python/att-string-join.html )

我就尝试看能不能把列表里的元素连起来,可以,成功得到我想要的形式:

from bs4 import BeautifulSoup

html = open("biliVideoPage.html", "r", encoding="utf-8")

soup = BeautifulSoup(html, "html.parser")

tags = soup.select(".tag-link > span")

print(tags)

tag = []

g = ""                            # 定义一个空字符串。

for ta in tags:

print(ta.text)

oneTag = ta.text      # 遍历出来的想要将它们连成一个字符串的几个字符串。

g = g+oneTag+","    # 用加号+,不成功,不是想要的。

tag.append(oneTag)    # 把要连在一起的字符串放进列表里。

print(tag)

print(g)                           # 不成功,不是我想要的。

# 以t作为连接的间隔符号,即将列表里的元素连接起来形成一个字符串,连接时以空格隔开。

t = " ".join(tag)               # 成功,是我想要的形式。

print(t)

结果:

费了一些时间研究这个。最后也解决了。其实还想把频道标签和普通标签做一个细分,发现好麻烦,就不做这个了,直接上面这样的标签集合也可以了。

--随机休眠几秒:

发现休眠的语句不能放进函数里,我放在getData函数里,它报错了:

说:

我把它放到外面。啊,我以为我放到了函数外,其实不是,我放到了main()函数里,但它就没报错了。为什么呢?搞不清楚。

啊,上面的休眠语句我放错位置了,怪不得测试的时候感觉都没有停顿。要放到getData的循环里来:

--获取目标数据遇到的问题和发现:

getData函数中:

1、日期时间

已改正确的代码:

# 获取视频上传日期和时间

data3 = soup.select(".video-data > span")

# print(date)                                 # 测试。

# print(date[2].text.replace(" ", ""))        # 测试。

# print(date[2].text.replace(" ", "")[0:10])  # 测试。

# print(date[2].text.replace(" ", "")[10:])   # 测试。

dateTime = data3[2].text.replace(" ", "")

date = dateTime[0:10]                         # 日期

videoData["date"] = date

time = dateTime[10:]                      # 时间

videoData["time"] = time

开始的时候,是这样写的,省了一步,把切片放在同一句,这样会报错。:date = data3[2].text.replace(" ", "")[0:10]

但是我把一页的网页源代码复制保存到html文件中,用作测试,像上面这样合在一起写是没问题的。但是动态爬取网站网页的时候,就报错了,说是字符串“str”中没有“text”这个属性。后面分开写,就没有报错了。

2、总播放量和总弹幕数

发现的:

在获取视频公布日期时间的时候,发现总播放量和总弹幕数也在这一层级下:

data3 = soup.select(".video-data > span")

之前是,总播放量和总弹幕数都是分别查找的,每个都select一次。因为报错,在重新测试时发现需要的数据都在上面这个层级里,所以为了减少搜索的操作次数,提高效率,把日期时间、总播放量、总弹幕数,都在这个层级里匹配出来,直接搜一次,然后在搜到的内容里把这几个数据逐一匹配出来。为什么之前我没看到呢?或者我没想到?

3、评论数

发现的:

# 获取评论次数comment = soup.select("div.b-head > .b-head-t.results")

# print(comment)                 # 测试。

# print(comment[0].text)         # 测试。

comment = comment[0].text

if len(comment) != 0:

videoData["comment"] = comment

else:

videoData["comment"] = " "

我用保存的html文件测试的时候,搜出来没有评论数,为空。可是我保存的这个视频详情页源代码文件,是排名第一的,有很多评论的。

我打开网页,用f12看了网站上的网页,这里是有数据的,但是我保存的也正是这个视频的详情页,我也用ctrl+f找到了这个代码的位置,我保存的源代码中,确实是没有数据的。

奇奇怪怪,明明都是同一个视频的网页源代码,只不过一个是我爬下来然后复制保存的,一个是我直接在浏览器上用f12看的。干嘛要区别对待。没事,没有数据也没太大关系。但是我肯定要加个判断,不然遇到为空的话,就会报错的。于是我加上啦。

4、投币

已改正确的代码:

# 获取点赞、投币、收藏、分享数data4 = soup.select("div.ops > span")

like = data4[0]['title'][3:]                   # 点赞数。去掉前面的“点赞数”3个字。

videoData["like"] = like

coin = data4[1].text.strip()            # 投币数.没有则是文字“投币”。

videoData["coin"] = coin

collect = data4[2].text.strip()          # 收藏数。没有则是文字“收藏”。

videoData["collect"] = collect

share = data4[3].get_text().strip()  # 分享数。没有则是文字“分享”。

videoData["share"] = share

我测试时是用直接用print的:

like = soup.select("div.ops > span")

print(like)

print(like[0]['title'][3:])

print(like[1].text.strip())

print(like[2].text.strip())

print(like[3].text.strip())

所以测试时才没有出现问题。等我复制到getData函数中,就是:

like = soup.select("div.ops > span")

print(like)

like = like[0]['title'][3:]

coin = like[1].text.strip()

collect = like[2].text.strip()

share = like[3].text.strip()

运行,在coin这里就直接报错了,说是字符串“str”没有“text”这个属性。

我还纳闷,测试时很完美啊。怎么就字符串了没有这个属性了。

我就猜测有可能是.text不行,换上了.get_text()这种形式,还是一样的报错。

研究了好一会,我对str这个报错的提示很费解,我在测试文件里打印了查找到的代码,里面确实也有text这个内容啊,是html语句没错呀,怎么就str了呢?

然后盯着coin这一句代码,突然发现了,这里的coin = like[1].text.strip()中的like,已经不是查找出来的那个like了,而是上面这个的like:like = like[0]['title'][3:],这里的like就是字符串str。是变量名的问题,导致报错了。后面改了变量名,就没报错了。

5、关注人数

已改正确的代码:

# 获取关注人数follower = soup.select(".has-charge > span")

# print(follower)                           # 测试。

# print(follower[0].text)               # 测试。

if follower is True:

if follower[0].text is True:

follower = follower[0].text    # 看到0人关注数的里面的数据是空的。所以要判断一下是空列表还是里面有元素。

videoData["follower"] = follower

else:

videoData["follower"] = " "    # 无关注者,用0表示。

else:

videoData["follower"] = " "      # 爬取的时候,遇到过没有列表follower。可能网页关注数的代码位置不是所有的都在这个地方吧。

测试一个列表页的20个详情页时,有些详情页的爬取是成功的,有些则报错了,follower[0].text,说是下标超出了范围。我的下标可是0啊,这都超出范围,说明为空列表。

马上才想到有可能关注者为0,然后特地找了一个关注者为0 的用f12查看,果然这里的html代码这里是没有数据的。所以我加上了一个判断:

if follower[0].text is True:

follower = follower[0].text    # 看到0人关注数的里面的数据是空的。所以要判断一下是空列表还是里面有元素。

videoData["follower"] = follower

else:

videoData["follower"] = " "# 无关注者,用0表示。

改了后再次运行,快爬完20条视频详情页的时候,又报错了,if follower[0].text is True:这里,说是没有什么具体我忘了,当时我在注释里简单描述了。

所以又再加了一层判断,判断是否有follower这个对象,是对象吧?反正就是这个follower。就没有报错了。

6、标签

以防报错加上判断:

# 获取视频标签tags = soup.select(".tag-link > span")

# print(tags)                           # 测试。

tag = []                                    # 用来存放一个视频的全部标签。

for ta in tags:

# print(ta.text)             # 测试。

oneTag = ta.text

tag.append(oneTag)

# 以t作为连接的间隔符号,即将列表里的元素连接起来形成一个字符串,连接时以空格隔开。

tag = " ".join(tag)

# print(tag)                              # 测试。

if len(tag) != 0:

videoData["tag"] = tag

else:

videoData["tag"] = " "     # 没有标签则用一个空格表示。

基于上面出现过几次为空的情况,虽然在视频标签这里还没有报错过,我还是直接加上一个判断吧,万一有人一个标签都没给视频加上呢?免得到时遇到程序又来一次崩溃。

7、账号描述

已改正确的代码:

# 获取up主昵称和账号描述upInfo = soup.select(".up-info_right > div")

upName = upInfo[0].a.text                      # 有两个a标签,但好像是只返回找到的第一个。

videoData["upName"] = upName          # up主昵称。

if soup.select(".up-info_right > div.desc") is True:

info = upInfo[1]["title"].strip()                # 账号描述。

videoData["info"] = info

else:                                     # 看了网页,有些是没有简介的,即没有简介这部分代码。

videoData["info"] = " "# 爬取的时候,遇到过没有title这个属性的报错:info = upInfo[1]["title"].strip()这一行,说KeyError: 'title'

测试一个列表页的20个详情页时,有些详情页的爬取是成功的,有些则报错了。

info = upInfo[1]["title"].strip()这一行,说KeyError: 'title',说没有这个title属性。

我想到了,有些人也可能没有账号描述。我特地找了一个没有账号描述的,和一个有账号描述的对比,用f12看到,有描述的这里有3个div,第二个div就是“title”。没有描述的只有两个div,直接没有描述这部分的代码。

对这个我还苦恼了好一会,不知道怎么加判断,或者也可以不要账号描述这部分也行了。后来想了一下,直接精确查找描述这部分的代码,然后判断是否存在,存在的就直接拿,不存在就用个空格填上这个位置。就没报错了。

8、没报错了,但不对劲的地方:

终于没报错之后,测试了爬一个列表页里20个视频的详情页,发现有三个数据都是为空的:

为空的分别是:

评论数:'comment': ' ',

关注数:'follower': '0',

账号描述:'info': ' '

下面我把关注为空的,改成用空格表示了,不再用0,上面的也改回来了,但截图就还是0的。

看来要不就不要这三个数据,要不就要去发现什么原因导致的。上面这些通通都是排名靠前的视频,这三个数据都是有的,但解析出来却没有诶。

评论数:

拿一个视频详情页源码测试,复制粘贴到html文件中,查找发现,评论那里的数据也是没有的,但在网站上f12,看到是有数据的。但是程序爬下来的网页源码里就是没有。好吧,我不要这个数据了。

后面顺便又测试了2个另外保存的网页源码,源码中也是没有评论数的数据的,我放弃,爬取下来的网页都没有这个数据存在,打印出这条html语句,里面都是空的,没有数据。我真的放弃这个数据了。注释掉了。

关注数、账号描述:

我把这两条分开写了,之前是在同一个查询语句里摘出来的,现在各个精确到各自那条语句:

# 获取up主账号昵称upInfo = soup.select("div.name > a.username")

upName = upInfo[0].text

videoData["upName"] = upName   # up主昵称。

# 获取up主账号描述

desc = soup.select(".up-info_right > div.desc")

if len(desc) != 0:                   # 没有描述返回的是一个空列表。

info = desc[0]["title"].strip()

videoData["info"] = info

else:                                      # 看了网页,有些是没有简介的,即没有简介这部分代码。

videoData["info"] = " "   # 爬取的时候,遇到过没有title这个属性的报错:info = upInfo[1]["title"].strip()这一行,说KeyError: 'title

现在重新再测试一次爬一个列表页里面的20个视频详情页,并打印出来看看我们要的数据对不对。

欧耶,成功了。

原来看着这些密密麻麻的数据,也会觉得很好看很漂亮,这应该是写代码才能看到和体验到的美丽。

后面我把账号描述info这个键改成了desc,表示描述,觉得这个名字更容易辨认和理解。

匹配部分调试完毕,真的用了好久啊,用了今天一天了。

明天要写保存数据这方面的,真的没讲过怎么讲字典放进数据库啊,看来又要慢慢地找慢慢地做了,因为我快不了呗。慢慢~慢慢没有感觉~~慢慢~慢慢没有….不知道为什么突然想到这句歌词,诶呀,保持微笑离开。23:20

20201204

14:45

--作死路上的感觉

今天打开网站搜这个关键词,想看看50页之后是不是就是空的。搜索的时候默认第一页,网页是顺利打开的,可是我点后面某一页,居然显示服务器没响应还是繁忙什么的具体忘了,就是没有网页返回来,打不开网页。点了几次,都是空的。

是我昨天弄得太多了被发现了,被禁了?!!昨天是测试了好多次,但也是有把握度,没有很频繁,只是一开始休眠放错了位置,很快也改回来了。之后都是在20个详情页之内的测试,因为保存下来的html网页源码并不具备代表性,不然我也不会爬那么多次的。

难道是因为这样被发现了吗?呜呜,我还没开始,网址就被废了吗!我还不知道怎么解决这些情况呢,不知道什么代理IP什么的,不知道哪里找,怎么用呢。然后又点了几次,居然打开网页了,点其它也,也顺利显示出来了。

真松了一口气,要知道我真不懂怎么办呀,而且我也喜欢这个网站的,不会导致我以后用不了吧,那样呜呼哀哉。幸好幸好,难道是我网络的问题?不知道,不管怎样,胆小的我,对失去这个网站我还是很不开心的,于是我改了一下休眠的时间随机4—7s每次,这够慢了没,看出我的友好了吗,希望不要把我IP封了就好,慢点就慢点吧。

--获取过程中遇到的报错1、2、应对策略

报错1:

正式爬,爬到第6个列表页的时候,也就是爬了一百多个详情页都没问题,突然返回一个报错:

看来这个网站的网页,总有一些是不太对劲的。现在居然又没有标题了。看来都要加个判断是否存在才行了。好浪费哦,这6页还是花了好些时间的。要不后面分几次爬吧,不然一次报错,前面爬到的都没了。

报错2:

又遇到一个报错,而且已经爬了快半小时,到第9个列表页的时候,突然中断了,时间又打水漂了。我设的是10页啊。下次设置一次只爬5个列表页好了。

网上查了为什么,说是有三个原因:你的请求被网站封了。你的网络出现了断网。你的代码有问题。

(来源:[WinError 10060]错误_Mr.小白-CSDN博客 https://blog.csdn.net/cjx14060307101/article/details/100113674 )

我就认为是后面两个原因的其中一个好了。

我还是把时间日期、总播放量、弹幕那里分开写吧,然后逐个再加个判断是否存在好了,报错真的伤不起,我真怕自己被封了。

--报错3-保存字典数据到数据库:模拟的数据总在join这里报错、测试、原因、解决

模拟匹配出来保存成字典形式的数据,来测试将字典数据保存到数据库。我不会。

搜索了一下python sqlite3 怎么把字典存入数据库中,不会,我照猫画狐,保存的代码语句是参考下面这篇写的。试一下能不能行参考的代码能不能行,还是报错了。

模仿来源:Python优雅的将字典数据存入数据库中_神薯片-CSDN博客 https://blog.csdn.net/weixin_39020133/article/details/106519547

说我连接成字符串时,整型的元素不可以。

还是用回列表的吧,字典的要找到合适的材料自学了才行,首先合适的材料都还没找到呢。19:32

20:00

我全部又加上了列表的存储形式。

然后再测试创建数据库,这个是成功的。接着测试将列表数据写入文件,按照老师爬豆瓣时那样写的,可还是报错了,错误也是上面的这样的,在连接join这个语句报错。

字典的时候也是报这样的错。我对把字典存入数据库不懂,我是按照列表那样子的思路来做的,不同点只是用键来取出值来,就和列表一样,列表还不用键什么,直接取就行。所以我不是按字典的思路把字典导入数据库,而是用列表的思路来把字典导入数据库,所以并没有方便到,反而比列表更麻烦。

这样做,只因为我不知道怎么写把字典导入数据库的语句。我是在尝试用字典的形式存储爬下来的数据,尝试把字典导入excel中已经成功了。然后又尝试把字典也导入数据库中,只能用列表那样的思路做,没办法,不会啊。

但是用列表的思路把字典导入数据库中,理论上就和列表那样做到了,但是在连结join就报错了。

我也不明白为什么连结就不行,就和豆瓣那个一样啊。因为字典我不懂,而且就算用了列表的思路做,理论上是没问题的,但现在就是一直在这个地方报错。所以我只能认为是我不知道哪里写错导致的,而且我自己没能力发现。于是就放弃了字典形式,用回列表形式吧。

列表形式我是有信心的,各步原理我也了解,老师也详细讲过了的。但是,改成列表之后。在测试时还是报错了,连结这里,还是这里。

我想没理由啊,豆瓣那里老师将字符串的数据加了对双引号进去,我也加进去了。数字型的老师跳过,我也一样跳过了。然后连结,我也是这样连结了。为什么豆瓣那里有字符串那样的和数字型那样的,连结就不会报错,而我现在这里也是有字符串那样的和数字型那样的,为什么我这里就报错了的?

这个我有信心,一定是哪里有差异,我没有发现到。

思路就是这样的,我的思路没有错,这个不用太质疑。我一定要找出原因,到底有哪里不一样,和豆瓣那里有哪里不一样?

测试过程:

既然报错,我又自己写了一个很简单的例子来检查:

a = ["sd", "sdf", 1, 2, 3]print(a)

b = ", ".join(a)

print(b)

结果:

a 就是我们爬到的一部电影的数据的形式,有字符串有数字型的。这里明确就报错了。

明明本质上是一样的,为什么这里就会报错的?

我一直看着打印出来的列表,老师之前也打印出来过匹配出来的放到列表里的数据,没什么差别啊。也是这样啊。到这里我还是没看出什么问题来。

然后我又模拟了给字符串型的加上一对双引号后的形式:

a = ["sd", "sdf", 1, 2, 3]

a1 = ['"sd"', '"sdf"', 1, 2, 3]

print(a)

print(a1)

b = ", ".join(a)

print(b)

结果:

看到这打印出来的两个列表,我突然恍然大悟。不同,和豆瓣的确实是有不同。

豆瓣的数据是从网上爬下来的,经过给字符串型加一对双引号、数值型不加这个步骤,再存到列表里后,形式是这样的:

a = ["sd", "sdf", 1, 2, 3]

a1 = ['"sd"', '"sdf"', 1, 2, 3]

a2 = ['"sd"', '"sdf"', '1', '2', '3']

print(a)

print(a1)

print(a2)

b = ", ".join(a2)

print(b)

结果:

我模拟的数据和爬下来的数据是有差异的。

爬下来的数据不管是字符串还是数字,都是字符串类型的。数字两边都是有引号的。而我模拟的数据,里面的数字就是数字,不是字符串型的啊。原来差异在这里。怪不得豆瓣那里连结列表的元素没有报错过,是因为那里的都是字符串型的啊。我没完全熟悉这些数据的形式和样子,自己模拟数据的时候,就没模拟对。

这么看来,我真正爬网页的时候join这里这些代码反倒不会报错。是模拟测试的锅。但测试很重要,叫它可爱锅吧。

太好了,困扰了好久,能发现也是有收获了。

现在这么看来,我字典那里用列表的思路来存储又能继续下去了。好,列表,列表思维的字典,这两种形式我都要做。等我自学会字典的存储代码后,再来用字典的思维把字典数据导入到数据库吧,哈哈哈。

太棒了我,众多的未来会继续遇到的问题,今天解决了一个,未知的问题数量减去确定的1。

(20201205前面的报错:“说我连接成字符串时,整型的元素不可以”。这个报错是因为我模拟的数据不对造成的。今天改正了模拟的数据,连结成字符串这里就没有报错了。所以又来试一下参考别人的那些保存代码可不可行,一样的保存语句,我运行了,还是不行:

源代码:

videoList = [{"link": "https://123.com", "title": "what are you doing?", "view": "24", "like": "0"},

{"link": "http://baidu.com", "title": "【I am 】doing nothing.", "view": "102", "like": "55"}]

conn = sqlite3.connect("biliTest.db")

cur = conn.cursor()

for video in videoList:  # data是一部电影的信息。

# 给字符串两边加上双引号括起来

for key in video.keys():  # 获取下标,每一个下标代表一个元素,相当于一列。

# print(key)

if key == "view" or key == "danmu" or key == "like":  # 下标为4和5的元素是数值,不需要改成字符串。

continue

video[key] = '"' + video[key] + '"'

# print(video[key])

print(video)

# 下面部分参考网上的,将字典导入数据库,失败的。

table = "biliEng2"

keys = ", ".join(video.keys())

values = ", ".join(['%s']*len(video))

print(keys)

print(values)

sql = """

insert into {table}

({keys}) VALUES ({values})""".format(table=table, keys=keys, values=values)

print(sql)

cur.execute(sql, tuple(video.values()))

conn.commit()

cur.close()

conn.close()

print("save finished.")

table那里开始就是模仿的。运行报错了:

反正昨天(20201204)以列表思维保存字典数据到数据库的已经写好了,后面又发现了模拟的数据有问题,现在单纯只是顺便再试一下这些从网上模仿的语句,不行就算了。)

因为我决定要分批爬取了,所以我得考虑多次导入数据会不会覆盖掉前面已经保存的。

多次保存数据到数据库:

验证了,数据库会接着后面存储,不会覆盖,和之前豆瓣我存了多次发现的一样:

# 将列表数据导入数据库。

# 数据库和数据表创建好之后,存入一次数据,后面再次存入数据,会自动添加到后面,不会覆盖掉前面存入的。# videoList = [['https://123.com', 'what are you doing?', '24', '0'], ['http://baidu.com', '【I am 】doing nothing.', '102', '55']]

videoList = [['https://hanju.com', 'it is ok.', '4', '2']]

conn = sqlite3.connect("biliTest.db")

cur = conn.cursor()

for video in videoList:

for i in range(len(video)):

if i == 2 or i == 3:

continue

video[i] = '"'+video[i]+'"'

#     print(video[i])

# print(video)

# print(", ".join(video))

sql = """

insert into biliTestEng

(link, title, date, time)

values(%s);""" % ", ".join(video)

print(sql)

cur.execute(sql)

conn.commit()

cur.close()

conn.close()

print("保存到数据库完毕")

我写了两条videoList,模拟多次存储,看到数据库中新增的数据是接着的,不会覆盖。

--多次保存数据到excel的思路:

excel的多次存入我也考虑好了,只要改变存到第几行就行。并且启动覆盖,避免有时候行数出错导致在已有内容的行写入失败而程序崩溃。真没注意到行数没写对,失去一两条数据没太大问题,崩溃就烦人多了,我都决定少量分批爬取了,情况是这样得适应,虽然我也想一次性爬完,但中途报错又重新来太浪费时间了。明天继续,大概要进入尾声了,耶。1:05

20201205

14:30

SQL日期数据类型,格式了解:

SQL Server 和 MySQL 中的 Date 函数 | 菜鸟教程 https://www.runoob.com/sql/sql-dates.html

--作死的路上:远程主机强制关闭了一个现有的连接、解决参考

正式爬取,爬了7个详情页,就报错了:

搜索大概是说被服务器认为我是攻击行为,断开了,大概就是被发现了,我的行为被认为是异常的。可能在作死的路上了吧,为啥豆瓣这么顺利的,连休眠和超时都没设置过都轻易爬下来了。可能老师就选了一个比较松的网站来教学吧。我要用到实处到底什么时候才成功呢?至今学了这个还没获取到我想要的数据nie~

根据下面这个,加上了response.close()这句代码,加了socket,我也不知道是什么,类似等待超时的。并且再添加了一个爬完列表页后休眠2s。

(来源:【Python爬虫错误】ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现_菩提树下静修身_新浪博客 http://blog.sina.com.cn/s/blog_c32439660102x1xp.html )

其它相同参考,以增加了解丰富度:

1、【Python爬虫错误】ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接_IllegalName的博客-CSDN博客 https://blog.csdn.net/illegalname/article/details/77164521#

2、python中关于

3、socket.setdefaulttimeout()_anambiousGKN的博客-CSDN博客 https://blog.csdn.net/anambiousGKN/article/details/100512340

socket应该写在哪个地方的参考:

1、(有很多实例可参考位置)

Python socket 模块,setdefaulttimeout() 实例源码 - 编程字典 http://codingdict.com/sources/py/socket/2278.html

2、Python:[WinError 10054]远程hos强制关闭了现有连接 - 问答 - Python中文网 https://www.cnpython.com/qa/155172

其它:Python web scraping Zacks网站错误:[WinError 10054]远程hos强制关闭了现有连接 - 问答 - Python中文网 https://www.cnpython.com/qa/418743

按照网上搜到的办法增加了三条语句。刚刚试着爬1个列表页即20个视频详情页,成功了,没有报错或被发现。还是一把老泪想要流下啊。并且也保存了,因为写好并测试好保存的函数啦。

现在就算是一个列表页也要保存,毕竟报错真的随时都可能遇到。之前爬了9个列表页在最后关头就报错了,也没保存到,浪费了时间也增加了被认出的风险。

还是少量多次爬取好啊,就算报错了投入时间每次也不会很多就几分钟。不过这都是基于容易报错的情况的,要是不会被强制断开,我也想一次弄完。还是老老实实吧,这个方法是目前最有效率的方法了。

--多次保存数据到数据库时,忘记注释掉创建库函数,保存失败

我又尝试爬了第2个列表页。因为忘了注释掉创建数据库和数据表这个函数的调用,导致没有把第2个列表页的内容保存到数据库中。

但有保存到excel中,我是同时进行两种方式的保存的。所以我把excel表中的数据复制到数据库里了,右键点submit提交,就会保存到数据表里,不点提交是还没有保存的。

--问题:excel追加的数据会覆盖掉前面已有的数据

有一个问题是,excel表并不如我想象的那样设置好写入的起始行后,就会在后面接着写入。而事实并不是这样的:

看到,前面写入的20条数据没了。原来它每次都是在整个空表里规划的,并不会保留前面已写入的数据。

难道是我那个cell_overwrite这个设置吗?不懂。然后想把数据库中的复制到excel表中,不合适,没有分开的,数据连成一条字符串那样的,前面覆盖掉的20条数据怎么办呢?19:35

21:30

--excel多次追加数据:不覆盖旧数据

我搜了excel怎么追加数据不覆盖以前的,已经找到合适的参考了:

python,Excel表格追加数据,不覆盖原数据。_u013291301的博客-CSDN博客 https://blog.csdn.net/u013291301/article/details/106630690

主要是用了一个excel写入的库和一个读取的库。

它的追加也并不是在原表上追加,而是通过读取已有的数据,复制到一个新的表中,相当于写入数据,只不过这个数据是通过复制已有的来获得的。然后再写入新的数据,即追加新数据。

关键一点就是保存,保存的时候用相同的名称,即sheet表的名称、excel文件的名称都和原来的一样,那么新保存的文件因为重名,里面的表也因为重名,而将旧的覆盖掉替换掉了。本质上其实还是写入一个新的表。理解弄明白这个原理,是通过看了几篇别人的代码理解下来的。只看一篇还真搞不懂意思。

之前觉得xlwt这个库的库名有点难记,因为我不知道这些字母有什么含义,也很模糊不是明确了解这个库用来干嘛的那种,都是照老师那样做的,其实不太明白每一步到底是在干嘛。就是知道我要创建一个excel文件要这样写,创建新的sheet表要这样写,其实真的没思考过为什么要这样,为什么是这个方法,为什么是这样写,都没有想过,老师说这样写那就这样写了。

刚才看了好几篇别人的代码和讲解之后,突然对这些就有了清晰的认识。之前是在这样做,但没有认识。原来对自己这一步在干嘛有一个清晰的认识,是这么爽的。之前是老师这么写我就这么写而已。

之前一直对xlwt这几个字母没好感,只能死记x、w、l、t,这样子,还经常忘了这几个字母的顺序。其它的库起码名字还是有点意思可想的。看了这几篇之后,尤其是看到介绍,很明确地说,一个是写入用的,一个是读取用的,一下子觉得这几个字母很好记,很有顺序,因为我知道它们的意思了。

xlwt:excel write。写入excel。

xlrd:excel read。读取excel。

是不是特别好记,并不是没有含义地用这几个字母明命名的。现在终于知道了。不用再费劲记了。

这方面的回答集合链接:

xlwt写入excel表不覆盖前面的数据 site:blog.csdn.net - 搜狗搜索 https://www.sogou.com/web?query=xlwt%E5%86%99%E5%85%A5excel%E8%A1%A8%E4%B8%8D%E8%A6%86%E7%9B%96%E5%89%8D%E9%9D%A2%E7%9A%84%E6%95%B0%E6%8D%AE+site%3Ablog.csdn.net&_ast=1607173818&_asf=www.sogou.com&w=01029901&cid=&s_from=result_up&sut=7456361&sst0=1607181450012&lkt=0%2C0%2C0&sugsuv=006B1754DF6840DF5D7E2CF4F0384832&sugtime=1607181450012

我已看的几篇讲解:

这篇特别好,让我了解了很多参数意思,虽然我没这方面的需求。

python中使用xlrd、xlwt操作excel表格详解_python_脚本之家 https://www.jb51.net/article/60510.htm

多测师_Python(写入 excel 操作 xlwt 模块)_多测师_郑sir-CSDN博客 https://blog.csdn.net/Mark_Zhengy/article/details/106067868

【干货】python xlwt写入excel操作_未名编程-CSDN博客_xlwt写入excel https://blog.csdn.net/qq_44275213/article/details/107877761  没关注后面的没看。

向Excel写入新数据且不覆盖之前的数据_舟舟_新浪博客 http://blog.sina.com.cn/s/blog_7c13ee6d0102xc30.html

还有一个问题没解决,excel前面的20条数据,怎么从数据库复制后,一个一个填到单元格里呢?现在是,从数据库直接复制过来是一整条字符串,都合在一起了。有能够做到不合在一起的方法吗?先查查这个方面。没有答案,再重新爬取一次好了,起码有备选方案,能不重新爬,费点时间找方法也没问题。因为以后可能也有复制数据库里的数据到excel的需求,盲猜会不会有导出到excel之类的方法呢?另外也可以从这个思路,搜搜有没有把excel数据导到数据库的方法。感觉有的话,我会需要用到的。

这些就是明天要做的事情啦。23:55

20201206

15:08

测试在excel表里追加数据成功,没有覆盖掉已经存在的数据。

追加数据之前excel表的样子:

追加数据到excel的代码:

import xlrd

import xlutils.copy

# 多次写入excel,在后面追加,不覆盖之前的数据。book = xlrd.open_workbook("biliExcelTest.xls")  # 打开要修改的excel文件。

new_book = xlutils.copy.copy(book)  # 复制原来的excel进行编辑。

sheet = new_book.get_sheet(0)         # 选择要修改的sheet表。获取第一个sheet表里的数据。表的下标从0开始。也可以使用表名。

videolist = [{"a": "yi", "b": "er", "c": "si"}, {"a": "yi2", "b": "er2", "c": "si2"}]

col = ["first", "second", "third"]

for i in range(len(col)):

sheet.write(0, i, col[i])                     # 表头。

for i in range(len(videolist)):                 # 追加数据。

video = videolist[i]

j = 0

for key in video.keys():

sheet.write(i+8, j, video[key])

j += 1

new_book.save("biliExcelTest.xls")     # 重名,保存则会覆盖掉旧的excel文件。

print("save finish")

运行上面这个代码,追加数据之后excel表的样子:

太好了,这个问题解决!

--未解问题:不会把数据库数据导出到excel

去搜怎么把sql数据库中的数据导出到excel,看到有很多说用sql server的,还有很多查询出来什么的,还有用代码用库什么的,搞不懂,不弄它了。

重新爬了一次前面的20条详情页。但是又遇到一个情况,就是数据库的主键id,我删除了重复的数据,后面再追加新数据的话,主键id跳了20个数,也就是id的数字被用了就会被用了,就算删了这部分数据,这部分被用了的id数字也不会重新分配给新的数据,主键下的数据是不允许重复的,删了也不能重新接着来。

我就是想看着它按顺序那样,空的那部分数字看着很不舒服。我就备份了原来的数据表,然后把它删了,再重新新建一个同名的空数据表,然后把数据复制过去。哈哈哈,方法再笨也是方法,能完美解决旧表带给我的审美不适。解决。

--保存数据到数据库报错:字符串里的双引号引发的歧义、解决

刚才试着爬取了2个列表页,写入数据库累计到第60条数据的时候,写入失败,报错了。说是报错位置在“Thank you”附近。

excel表是顺利保存了的。打开excel表看了,这个地方是这样子内容:

我把后面缺的数据复制到数据库里补上了,在数据库里的样子是这样子的:

一开始我以为是NBSP这样的空格导致报错的,可能是解码方面不行导致的。

但我记得豆瓣项目那里也有这样的空格代码块,是没事的,并不会报错。我的整体思路就是豆瓣项目那样的思路,各个地方都是一样的原理。要报错豆瓣那里早就报错了。

看到报错提示说是Thank you附近,这附近的话还有什么比较可疑的呢?双引号,这里有对双引号,这些杠杠单双引号都是容易造成歧义的地方。因为用sql语句写入数据那里给字符串加了一对双引号。

于是,我自己写了一个例子来测试了一下是不是这里双引号的问题:

a = ['当你说"Thank you"时,是里面的双引号导致写入数据库失败?']

conn = sqlite3.connect("biliTest.db")

cur = conn.cursor()

for i in a:

data = '"' + i + '"'

print(data)

sql = '''

insert into biliEng2

(link)

values(%s)''' % data

print(sql)

cur.execute(sql)

conn.commit()

cur.close()

conn.close()

print("save finished.")

保存失败:

改成加一对单引号:

a = ['当你说"Thank you"时,是里面的双引号导致写入数据库失败?']

conn = sqlite3.connect("biliTest.db")

cur = conn.cursor()

for i in a:

data = "'" + i + "'"

print(data)

sql = '''

insert into biliEng2

(link)

values(%s)''' % data

print(sql)

cur.execute(sql)

conn.commit()

cur.close()

conn.close()

print("save finished.")

成功:

果然是双引号的问题,把它改成单引号,就解决啦。

用这个思路,如果后面遇到字符串里本身已经有单引号的,也可能会报错崩溃的。根据感觉经验,标题用中文写的更多,中文里用单引号来强调的情况会比用双引号的少一点。故决定用一对单引号括起来。19:07

--应用所学python实现想要功能后的感受

20201207

现在不再学习和查找python方面的了,昨天为止,成功啦!耶!我学这个python成功实现了我想要的功能,

已经开始在应用啦!我的目标是获取我需要的数据,这个目标已经实现了。

我发表一下我的心情,嗯~怎么说呢,就有那么一些高兴开心吧,喜悦,平静的喜悦,我也没想到,根本不会高兴到心跳加速,喜跃于表,自己在那里笑,没有,就两个字平静的喜悦,淡淡的再浓一点点的程度,就这么多了。因为,轻松得到才会更让人想高兴大笑呀,这个过程中,真的不轻松啊,遇到报错,心很累的!一定是这可恶的小家伙,心累,心累消去了部分成功那一刻的开心。成功那一刻,比起开心地笑起来,再也不用陷入那种怎么搜索也搞不懂解决不了的报错中的煎熬的逃脱感,才更显著。这个标志没有了报错的完成,不是让人开心笑,更多是让我感觉终于可以轻松呼吸了,不用再经历那种煎熬了,从底部的黑暗时间上升到光明地面,就是成功的嘉奖啦。为什么是平静呢,现在懂了吧,高兴是飞跃空中,已经跳层啦。

果然我把标题的数据改成加一对单引号,是非常明智的。看了一下保存到的数据,后面遇到标题里本身含有双引号的情况真的不少。

--多次保存数据到excel忘记写起始行号、忘记关闭打开的excel文档

啊,我不是采取了少量分批多次爬取策略嘛,保存到excel文件的时候,每一次都要手动设置从第几行开始追加的。

我写这个函数就提醒过自己,一定要记住,按运行前一定要记得改第几行,谨记谨记!因为我知道,就算我这次注意了那次注意了这次也注意了那次也注意了这次也注意了,但永远不能保证下一次一定是注意的,所以,在这种情况下最好的办法,就是时时刻刻让自己注意注意谨记谨记。

我知道,但有个毛线用啊?,我穷,难道是我不知道自己穷才穷的吗,我知道我有很可能会出现不注意的时候,不管是我连续注意了100次200次之后,后面的每一次我还是很有可能会没有注意到。

对,就是刚才,刚才爬的40条把之前的40条给覆盖了,因为我根本没记得要改保存的行号啊,@##…!&%#¥%#,我骂了。我不会真正关心要改行号这件事,我知道,我完全知道,我很明白,有用吗,我提醒自己注意注意,谨记谨记,有用吗,这些根本敌不过我对它不关心的真正的本性。

本性是非常强大的,强大到它是非常自然的状态根本不需要努力它自己就会一直维持。有用吗?诶!?这个问题还没回答哟,千万别误会咯,有用。

起码昨天就一直记得,昨天每次运行都有记得改。今天我忘了,今天再爬取,又不会忘了。我想明天我还是不会忘了,因为我今天忘了,我还把它详细记录了。上次记录那个软件打卡,真是如此真实,连续打卡止于193天。唉,真是,当我决定学python,它坐上去的空位置已经有所属人了,它没办法继续坐着了,因为一开始那里只是一个空位置,谁都可以坐坐,但都不是谁的。

OK,我要记住咯。刚才覆盖的数据,我只能重新爬了,我不会把数据库里的数据导出成excel格式的。

我重新爬了,但是我忘记关闭excel文件了,我把它打开,插入了40个空行来放重新爬取的数据,但忘记关闭文档了,诶呀,我呀。记得下次关闭文件。

再重新~爬一次?算了,我都不好意思了今天,明天再补吧,虽然再轻轻一点那个运行小图标就行,就是刻意留着这种不完美的缺憾感,我看到应该有点不舒服对不对,希望能让我对这种错误更讨厌点再看到吧。

我在考虑写一个自动判断excel空行起始点的代码,这才是不会忘记的终极办法!好,写它。

--计算excel表行数:自动判断excel追加数据的行数起始点

写好啦。明天再试试看行不行。(可行)

import pandas as pd                         # 用来统计excel表的行数

get_sheet = pd.read_excel(excelpath, sheetName)  # 读取哪个excel工作簿中的哪个sheet表

# print(get_sheet)               # 测试。

# print(len(get_sheet))       # 测试。

row = len(get_sheet)         # 追加的数据就是在下一行开始追加:row+1

这个是读取表,通过拿到长度来获得行数。

还有其它的思路是通过拿到一行一行的值,一一判断是否为空,遇到空值的就停止统计,获得行数。

判断行数代码思路来源:

主要根据这篇,通过看其它增加对含义的理解。

用python批量统计Excel中的内容_shuyueliang1的博客-CSDN博客_python统计excel https://blog.csdn.net/shuyueliang1/article/details/88541276

python中如何获取excel表格中数据所在的行和列-11501126-51CTO博客 https://blog.51cto.com/11511126/2347566

python 对execl数据进行统计案例_chuqiao8512的博客-CSDN博客 https://blog.csdn.net/chuqiao8512/article/details/100770641

python读取excel的行数_清湖小妖的博客-CSDN博客 https://blog.csdn.net/weixin_44245949/article/details/103610914

python pandas 如何读写excel 获取表的行数 列数_DL_min的博客-CSDN博客 https://blog.csdn.net/DL_min/article/details/105512788

python数据分析,用python对excel表格操作_sunlight_meng的博客-CSDN博客 https://blog.csdn.net/sunlight_meng/article/details/108916946

对各模块的了解:

2019-11-2 python中操作excel_没人不认识我的博客-CSDN博客 https://blog.csdn.net/weixin_42555985/article/details/102872781

Python 使用xlrd 读取 Excel遇到错误 - 简书 https://www.jianshu.com/p/8640abf11297

python操作统计excel表格,生成新excel表格_tjiyu的博客-CSDN博客 https://blog.csdn.net/tjiyu/article/details/106018164

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值