python 爬取漫画简易爬虫

今天闲的无聊,所以准备看看漫画,但是发现大多数的漫画一页一页翻,可能会来不及加载,但是确实是很想看接下来的内容,慢慢等的话确实有点难受。

所以准备用Python写一个爬虫,来爬取相关的资源,下载到本地,之后用键盘的左右键翻看就好了。大不了在爬取漫画的过程中干点别的。

因为那个网站有点不可描述,所以我就简单说下过程,不贴图了。

首先是分析一下这个漫画的链接,是从哪里得到的。我这个是虽然有img但是实际上他的图片储存在了data-src里,所以我们先copy一下他的xpath //*[@id="content"]/div[2]/div[4]/a/img 然后将img后面添加上@data-src就能获取这个属性的内容了。

之后我们需要写一个解析页面的代码,然后将解析出来的图片进行保存就好了。这里我是用的函数来写的,方便维护,毕竟Python爬取漫画还是挺多代码的。

1
2
3
4
5
6
7
8
9
def get_links(url):
"""获取所有的链接"""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
pagehtml = requests.get(url, headers=headers)
pagehtml_jiexi = etree.HTML(pagehtml.content.decode('gbk'))
links = pagehtml_jiexi.xpath('//*[@id="image-container"]/img/@data-src')
return links

首先是解析一下内容,先全部阅读漫画内容,让所有的图片在同一个页面上,之后获取所有的图片链接,再进行爬取。

然后就是判断图片的格式,这个是因为我爬的漫画是由png格式或者jpg格式的,所以写了个判断。

1
2
3
4
5
6
def judge_picture(url):
"""判断图片的格式"""
examplelink = url.pop()
pictureformat = re.findall(r'.*([a-z]{3})', examplelink)
pictureformat = pictureformat.pop()
return pictureformat

然后再就是进行下载了。这里用到了if,根据格式来命名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def downloads(newlink):
"""下载"""
links = get_links(newlink)
document_name = get_name(newlink) # 获取单个链接
picturefotmat = judge_picture(links)
a = 1
if picturefotmat == "jpg":
for link in range(len(links)):
if a % 50 == 0:
time.sleep(30)
onelink = links.pop()
picture_info = get_pictureinfo(onelink)
pictureid = re.findall(r'.*/([0-9]*).jpg', onelink)
pictureid = pictureid.pop()
with open(document_name + '/' + pictureid + '.jpg', 'wb') as mh:
mh.write(picture_info)
print("已完成" + pictureid + '.jpg')
a += 1
elif picturefotmat == 'png':
for link in range(len(links)):
if a % 50 == 0:
time.sleep(30)
onelink = links.pop()
picture_info = get_pictureinfo(onelink)
pictureid = re.findall(r'.*/([0-9]*).png', onelink)
pictureid = pictureid.pop()
with open(document_name + '/' + pictureid + '.png', 'wb') as mh:
mh.write(picture_info)
print("已完成" + pictureid + '.png')
a += 1
totalinfo = "文件夹:" + document_name + ",漫画链接:" + newlink + '\n'
with open('downloadinfo.txt', 'a') as info:
info.write(totalinfo)
print("完成")

之所以加了一些print,是因为爬取的过程中太无聊了,没有提示的话会疯掉的。

然后 重点说一下为什么要用到time,以及前面的try,time是因为反爬,虽然我爬的网站大概率没有,但是每隔多少图片休息一下还是好的。

之后那个try是为了防止超时,如果有自己写过的话,会发现有的时候爬着爬着,就不动了。这就是超时了,所以加上一个try进行抓取,如果超时就进行重新获取,然后如果3次都不行的话,就继续下一个。

当然实际上到底是不是这么写,我也不清楚,因为我确实没遇到超时的报错,因为我之前没加timeout,所以他会一直卡在一个地方不动,然后我直接加了timeout和try了。

具体的代码可以看我的GitHub库:https://github.com/datehoer/yellow

如果有什么不懂的可以在评论区留言,我会在看到的第一时间进行回复的。

python 爬取漫画简易爬虫

python 爬取传智播客作业题目

今天发一下我之前写了一会的关于爬取传智播客习题的爬虫。目前来说,其实是因为最近期末,然后想要爬取一下题库里的题,然后做一个题库出来,之所以这样,是因为老师并没有公布答案! 不过没想到传智播客居然是用 JavaScript 渲染的页面,而非普通的 HTML,难度很大对于初学者。

目前找到了想要的内容但是并不知道该如何爬取。

python爬取传智播客内容

首先在这里右键查看一下源代码,之所以如此,是因为我本来以为可以直接通过这里获取链接跳转的内容,然后爬取出来,但是没想到并没有,并且其实传智里面的页面代码是通过 JS 渲染的,所以应该通过 header 请求来获取数据。然后使用 F12 查看 Network,在寻找请求获取内容的时候,发现请求名为 list?status=&name=&pageNumber=1&pageSize=10&courseId=5b1d1d6e854e408b89043bb29c604313&type=1&t=1608267215390 这个的请求,里面的 preview 中,有想要获取到的内容 然后发现这里面的内容是一个 id,然后发现下面的题目的链接就是这个页面加上 id 即可。 所以其实通过 header 请求头,然后提取出来的 JSON 文件,再进行解析即可。 之后再获取题目里的内容即可。 其实这个我想了好久,因为当时不知道获取到的内容是 JSON,以为是字符串,然后通过正则来获取数据的时候,发现只能获取第一个匹配的,然后后来问了大佬才知道这是 JSON 的数据。

其实他这个是通过 JSON 传递的数据,然后里面是字典的镶嵌。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests_html
import re
import json

url = "http://stu.ityxb.com/back/bxg/my/busywork/findStudentBusywork?busyworkId=166955876c3b4bcf8ef39976dfe60e76&t=1608445306731"
url2 = 'http://stu.ityxb.com/lookPaper/busywork/166955876c3b4bcf8ef39976dfe60e76'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
'Cookie': ''
}

res = requests_html.HTMLSession()
r = res.get(url, headers=headers)

text = json.loads(r.text)
text_xz = text['resultObject']["danxuan"]['lists']
neirong = {}
changdu = len(text_xz)

for i in range(1, len(text_xz) + 1):
wenzi = text_xz.pop(0)
text_xx = wenzi["questionOptionList"]
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm)
for num in range(len(text_xx)):
xx_dan = text_xx.pop(0)
xx_nei = xx_dan['text']
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + xx_nei)

这里就能提取单选的内容了,然后再就是获取全部的内容就行了,但是发现有的作业里面只有单选或者只有判断之类的,然后我们可以通过 try 来进行报错处理,这样即使没有这个选项,也能运行下去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import requests_html
import re
import json

url = "http://stu.ityxb.com/back/bxg/my/busywork/findStudentBusywork?busyworkId=166955876c3b4bcf8ef39976dfe60e76&t=1608445306731"
url2 = 'http://stu.ityxb.com/back/bxg/my/busywork/findStudentBusywork?busyworkId=655d240321db424ea37f4b55c2f132d2&t=1608476055939'

headers = {
'User-Agent': '',
'Cookie': ''
}

res = requests_html.HTMLSession()
r = res.get(url2, headers=headers)

text = json.loads(r.text)
text_xz = text['resultObject']["danxuan"]['lists']
neirong = {}

for i in range(1, len(text_xz) + 1):
wenzi = text_xz.pop(0)
text_xx = wenzi["questionOptionList"]
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm)
for num in range(len(text_xx)):
xx_dan = text_xx.pop(0)
xx_nei = xx_dan['text']
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + xx_nei)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + '答案:')
try:
text_xz = text['resultObject']["duoxuan"]['lists']
for i in range(1, len(text_xz) + 1):
wenzi = text_xz.pop(0)
text_xx = wenzi["questionOptionList"]
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm)
for num in range(len(text_xx

)):
xx_dan = text_xx.pop(0)
xx_nei = xx_dan['text']
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + xx_nei)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + '答案:')
except:
pass

try:
text_pd = text['resultObject']["panduan"]['lists']
for i in range(1, len(text_pd) + 1):
wenzi = text_pd.pop(0)
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm + '\n' + '答案:')
except:
pass

try:
text_tk = text['resultObject']["tiankong"]['lists']
for i in range(1, len(text_tk) + 1):
wenzi = text_tk.pop(0)
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm + '\n' + '答案:')
except:
pass

try:
text_jd = text['resultObject']["jianda"]['lists']
for i in range(1, len(text_jd) + 1):
wenzi = text_jd.pop(0)
text_tm = str(i) + '.' + wenzi["questionContentText"]
print(text_tm)
with open('jsdx.text', 'a', encoding='utf-8') as f:
f.write('\n' + text_tm + '\n' + '答案:')
except:
pass

这就是 Python 爬取传智播客的作业题目的完整代码了,不过问题是需要复制链接,不过还算可以吧,以后如果改进的话会贴出来的。 不过其实很容易,就是解析前一页的数据,把里面包含链接的内容提取出来,然后再传入 for 循环即可,如果想要尝试的话可以自行测试,有不懂的随时问我。 如果有什么不会的可以在评论区留言,我会在看到的第一时间回复的。

python 爬取我的世界id,我的世界中英文id

其实如果是一直关注本站的读者会知道,其实这里最早只是一个做我的世界服务器的官网,虽然说我现在服务器也在开着,但是当时不知道哪根经抽了,就把这个当成博客了,不过其实还是关注着我的世界的。

先说一下任务,目前呢在网络上搜索我的世界 ID 的话,会发现 ne 那个搜到的大多都是好多年以前的内容了,比如说那张我记的好久好久好久以前就存在的 ID 对照图。

python爬虫爬取我的世界 ID 对照

就是这张,影响深刻,但是实际上随着年份的增加,我的世界的版本更新还是蛮快的,一些新的内容在这上面就找不到了,所以就萌生了一个做 ID 对照的网站的想法,但是数据从哪来呢?答案当然是百度,通过百度的查询我发现了一个老外的 ID 站做的很不错,所以呢,目标就设定为他,使用 Python 爬虫将我需要的数据爬取下来。

不过其实在最终目标确定前,还有一个其他的目标也可以操作一下,不过那个内容相对较落后了,所以还是选择了第一个选定的目标。

我们先看一下该网站,分析一下。

python爬取我的世界 ID

很简单的构造,就是中间内容然后上下都是些介绍之类的,然后我们发现他这个一个页面显示一点点内容,获取所有的内容是需要翻页的,但是我搜索了半天确实没找到,应该是写在了 JS 文件里,因为我看到他调用了好多 JS 文件,不过我并没有去找里面有没有跳转链接,当时其实想是,你不论怎么说其实内容也就那么一点,大不了我直接把每个链接保存下来嘛。

结果翻页的时候看了一下,发现他的链接很简单,就是把之前那一页加上了 /?加上了数字,代表页码,很舒服。

直接通过 for 循环就可以爬取每个链接了,然后看了一下一共 8 页。所以循环从 range(2,9),为什么从 2 开始呢,是因为他第一页没写页码,相对简单的方法就是循环还是 range(1,9) 然后呢,我们设置个判断,如果是 1 的话链接设置为首页就行了,不过我当时懒,直接复制出来了一份,先把第一页爬出来再循环其他的页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import requests
from bs4 import BeautifulSoup

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
}

url = "https://minecraftitemids.com/"
# 2 3 4 5 6 7 8
r = requests.get(url, headers=headers)
neirong = r.text
soup = BeautifulSoup(neirong, "lxml")
wenzi = soup.table.get_text()
length = len(wenzi)

with open("mclist.txt", 'a', encoding='utf-8') as file_object:
n = 1
for i in range(0, length, 20):
file_object.write((wenzi[i:i+20]))
if n == 10:
file_object.write('\n')
n = 0
n += 1

for a in range(2, 9):
newurl = url + str(a)
r = requests.get(newurl, headers=headers)
neirong = r.text
soup = BeautifulSoup(neirong, "lxml")
wenzi = soup.table.get_text()
length = len(wenzi)

with open("mclist.txt", 'a', encoding='utf-8') as file_object:
n = 1
for i in range(0, length, 20):
file_object.write((wenzi[i:i + 20]))
if n == 10:
file_object.write('\n')
n = 0
n += 1

print("爬取完成")

可以看到我们利用了两个库,requests 大家都清楚,BeautifulSoup 这个库也是一个非常实用的库,看过前面文章的都知道,我写的那个爬取知乎文章的爬虫也利用了这个库,比较适合抓取内容。知乎爬取全部内容 知乎爬取单页内容 感兴趣的可以了解一下,通俗易懂,哈哈。

然后呢,这个其实也就没啥好讲的了,也就是最后写入文件的地方可以说一下啊,为什么要加一个循环,这是因为如果不加循环的话,他写入的内容是一行文字,当然如果你用记事本看的话,开个自动分行就好了,但是我想直接写入的内容就是分好的,所以就

加了个循环,每循环 10 次换一下行,结果还可以吧就是有点乱,需要调整一下。

好了,文章就到这里了,如果有什么不懂的请在评论区留言,我会在看到的第一时间进行回复的。

python 爬取知乎盐选全部内容

没想到进阶版来的这么快,在发布了python爬取知乎盐选文章内容后,没想到居然这么快就要更新新的内容了。 在下午思考第一篇python爬取知乎盐选文章内容的时候,其实就把自动爬取目录内的其他内容的方法想出来了,但是本来没想这么快更新的,哈哈。 不过思来想去还是发出来吧,毕竟要不哪天就忘了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from DecryptLogin import login
from bs4 import BeautifulSoup
import re
import base64

lg = login.Login()
_, loginstauts = lg.zhihu(username='', password='', mode='pc')

headers = {
'user-agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"
}

url1 = "https://www.zhihu.com/market/paid_column/1178733193687175168/section/1178742737682350080"
url2 = "https://www.zhihu.com/market/paid_column/1178733193687175168/section/1178742849583083520"

# 获取链接
r = loginstauts.get(url1, headers=headers)
wenzi = r.text
soup = BeautifulSoup(wenzi, 'lxml')
lianjie = soup.textarea
lianjie = str(lianjie)

pattern = re.compile('"next_section":{"url":"(.+)","is_end":') # 正则匹配链接所在的文字
result = pattern.findall(lianjie)

texts = soup.find_all('p')

for text in texts:
with open("yanxuan.txt", 'a', encoding='utf-8') as file_object:
file_object.write(text.get_text() + " ")

list = result.pop(0)
print(list)

for link in range(0, 9):
r2 = loginstauts.get(list, headers=headers)
wenzi = r2.text
soup = BeautifulSoup(wenzi, 'lxml')
lianjie = soup.textarea
lianjie = str(lianjie)

pattern = re.compile('"next_section":{"url":"(.+)","is_end":') # 正则匹配链接所在的文字
result = pattern.findall(lianjie)
list = result.pop(0)

texts = soup.find_all('p')

for text in texts:
with open("yanxuan.txt", 'a', encoding='utf-8') as file_object:
file_object.write(text.get_text() + " ")

python 爬取知乎盐选全部内容

直接上一手代码,讲一下思路,首先先是获取文本内容,通过前面的文章,我们知道 了如何获取文本内容,并且明白了该怎么获取整个页面的html内容。

本来最初的想法是把目录里的每一个链接都复制下来,然后通过遍历来获取链接,因为我最初是真的没发现下一篇的链接是通过哪里获得的。然后今天下午的时候,认认真真(闲的蛋疼)的看了一下知乎盐选文章内容的源代码,发现原来跳转链接在他的底部textarea里,并且还是在里面的一个next_section里,让我一顿好找,不过找到就是最好的啦。

找到之后,我们只需要获取到跳转的链接即可了,只需要使用正则进行条件筛选就可以了。

1
2
pattern = re.compile('"next_section":{"url":"(.+)","is_end":')  # 正则匹配链接所在的文字
result = pattern.findall(lianjie)

也就是这一段代码,我们对获取的内容进行匹配筛选,即可获得链接了,不过在获得之后,还是会出现一个问题,就是获取的内容会储存在列表里,我们还需要把列表的内容读取出来才能使用。本来其实最早我的思路是使用循环,然后把获取到的链接储存到同一个列表里,然后利用循环读取即可,但是因为当时脑子可能抽了,把变量的值给改错了,前面虽然该出来了,但是后面的都没改,就会得到一个很尴尬的结果,就是所有的结果都是同一个,然后我就换了种方法,没想到刚换就找到了问题所在。不过也懒得该回去了。

通过列表的方法pop来对列表内容进行删除,并且将删除返回的值进行保存,然后当作一个数据进行储存。也就是这一段的内容了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for link in range(0, 9):
r2 = loginstauts.get(list, headers=headers)
wenzi = r2.text
soup = BeautifulSoup(wenzi, 'lxml')
lianjie = soup.textarea
lianjie = str(lianjie)

pattern = re.compile('"next_section":{"url":"(.+)","is_end":') # 正则匹配链接所在的文字
result = pattern.findall(lianjie)
list = result.pop(0)

texts = soup.find_all('p')

for text in texts:
with open("yanxuan.txt", 'a', encoding='utf-8') as file_object:
file_object.write(text.get_text() + " ")

其他的也就没有什么难度的东西了,不过如果有什么疑问,可以在评论区留下你的疑惑,我会在看到的第一时间进行回复的。

python 爬虫之获取标题和链接

今天我想分享一些关于SEO优化的基础知识,这些知识几乎每位SEO专业人员都会明白。一种SEO策略是在其他论坛上发布文章,首先发布一些具有技术性的文章,然后再发布自己网站的链接。最近,我在oschina论坛上发布了一些文章,但今天我没有太多新的内容要发布,所以我决定分享一段小代码,用于爬取我的oschina论坛内的链接和标题。这个过程非常简单,非常容易。

下面是Python代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from requests_html import HTMLSession

session = HTMLSession()
url = "https://my.oschina.net/u/4798232"
r = session.get(url)

for i in range(1, 12):
i = str(i)
url_xpath = '//div[@id="newestBlogList"]/div[1]/div[' + i + ']/div/a'
title = r.html.xpath(url_xpath, first=True).text
link_xpath = url_xpath + '/@href'
link = r.html.xpath(link_xpath, first=True)
a = "原"
if a not in title:
print(title)
print(link)
else:
print(title.replace(a, ""))
print(link)

这段代码使用XPath来操作,具体如何复制XPath可以参考您提供的文章中的动图示例。然后,我们导入所需的库并定义了要访问的URL。在循环中,我们通过XPath来获取链接和标题。

不过,注意到一开始有些文章的XPath中多了一个[1],解决这个问题时的方法是尝试不加[1],看看是否仍然可以获取文章的内容。此外,注意获取标题时需要使用.text属性来获取文字,但获取链接时不需要。

还可以进一步将标题和链接保存到JSON文件中,或使用openwrite来将它们写入文本文件中,然后可以在需要时读取它们。这将获取文章的所有链接,并通过查询文章内容的XPath来获取所有文章内容。

如果有任何问题或需要进一步的指导,请随时在评论区提问,我将尽力回答。

安装Docker Desktop报错WSL 2 installation is incomplete

以下是您提供的内容的格式化版本:


在看《python3网络爬虫开发实战》的时候,安装开发环境时,遇到了一个小问题,但是呢百度上面的回答大多不怎么样,不过没想到自己随便一试就把解决办法试出来了。

安装 Docker Desktop 时,出现了以下报错:

WSL 2 installation is incomplete

具体原因是因为 Windows 系统下的 Linux 内核的版本有点低,我们只需要前往更新地址,下载对应的 Linux 内核更新包,然后更新一下即可!

更新地址https://docs.microsoft.com/zh-cn/windows/wsl/wsl2-kernel

根据网页提示进行更新即可。

python 爬虫入门之requests-html

其实本来应该早一点发的,但是我用织梦后台编辑文章的时候,不小心点了网页的x号,于是乎,内容白写了,然后我又开始重新写了。

requests库,是一个第三方的Python库,用来模拟发送HTTP请求。它通常用于爬虫或接口的测试。与urllib等其他的系统库相比,虽然他们的功能相似,但是requests相对来说更简单、方便和高效。

首先我们先把这个requests-html安装一下,进入运行框然后输入 pip3 install requests-html 即可安装成功,在之后我们把该库导入即可:

1
import requests_html

接下来准备了一个小例子给大家,本来其实每句话都有分析的,但是由于是第二遍写,就不那么麻烦了:

1
2
3
4
5
6
7
import requests_html

# 导入requests-html库
session = requests_html.HTMLSession() # 创建一个session的变量,用来取代requests_html.HTMLSession()要不之后字太多而纸样只需要操作session
res = session.get("https://www.datehoer.com/") # get一下网址,这里我们用博客主页做演示
res.encoding = "utf-8" # 获取的编码格式
print(res.text) # 输出获取的内容

最简单的一种方法。 之后我们来介绍一下其他的方法,也就是requests-html的进阶。

获取链接:

1
print(res.html.absolute_links)

这个就是获取链接的方式,绝对路径,这样就会直接获取完整的链接’https://www.datehoer.com/wdsj/'而如果直接获取链接呢?

1
print(res.html.links)

‘/wdsj/2020/1111/42.html’ 则会出现上面这样不完整的链接,各有各的用处吧,不过大多数还是要加一下绝对路径的链接的。

XPATH

这个的抓取我们看一下动图 requests-html

获取的内容为 /html/body/article 这个:

1
print(res.html.xpath("/html/body/article", first=True).text)

这个就是把该 xpath 代表的内容输出出来的代码。 而 xpath 有 4 个参数:

  • selector,要用的 XPATH 选择器;
  • clean,布尔值,如果为真会忽略HTML中 style 和 script 标签造成的影响(原文是 sanitize,大概这么理解);
  • first,布尔值,如果为真会返回第一个元素,否则会返回满足条件的元素列表;
  • _encoding,编码格式。

然后我们还有 html+css 获取的方法

还是以博客的主页为例,我们要获取头部标签内的内容,而我们 div 里有一个 class 为 header 的标签,我们就获取它的内容吧。

1
2
hc = res.html.find("div.header", first=True)
print(hc.text)

只要写出该内容的标签传递关系即可获取内容:

1
主页 技术分享 日常学习 法制专栏 我的世界 关于我 检索标题 智能模糊 搜索

这就是具体的获取内容了,相应的,具体你需要什么内容需要通过属性来进行判断。

1
print(hc.search("主{}")[0])

比如说这个,这个就是查询内容了,搜索之前获取的 div.header 里有没有以主为开头的内容,然后返回获取的值。再比如说还有许多的方法,就不一一在此列出了,其余的我们且听下回分晓!

python 外星人入侵 完整版

差不多用了三天的空闲时间,把这个案例看完了一遍,并且实际操作了一下,其实难度确实不高,很适合我们这样的新人去操作。不过其实遇到了许多的问题,但大多都是我的问题,做的我是心态崩了。

今天最后做play按钮的时候,怎么也不出效果,把 game_active 改为 False 就显示黑屏,而换成 True 显示内容但是没啥卵用,因为不是静态的。当时是真的不想做了,因为确实没有啥错误,出去吃了个饭,再仔细一看发现我是真的蠢!

1
2
3
4
5
6
7
8
9
while True:
# 监视鼠标和键盘事件
gf.check_events(ai_settings, screen, stats, board, play_button, ship, aliens, bullets)
if stats.game_active:
ship.update()
bullets.update()
gf.update_bullets(ai_settings, screen, stats, board, ship, aliens, bullets)
gf.update_aliens(ai_settings, screen, stats, board, ship, aliens, bullets)
gf.update_screen(ai_settings, screen, stats, board, ship, aliens, bullets, play_button)

这一段,最后的 gf.update_screen 应该在 if 外,因为它是做出那个静态效果的,但是我当时把它放到了 if 里,所以改成 False 时,显示黑屏,我当时真的找了半天,因为他这个如果你没改 False 的话是没有任何问题出现的,最后随便一看,发现了这个错误,把我气的。

还有一些非常蠢的错误,基本上全是自己的失误吧,哎,说多了都是泪。

其实很重要的一个模块就是 pygame.sprite,毕竟你要修改游戏要进行交互等等吧,很重要。

不得不说,细节决定成败,这句话非常有道理!

我就把外星人、计分板和按钮的 Python 文件发一下源代码,其余的还是改成附件上传吧,毕竟有点小多。

计分板的 scoreboard.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import pygame.font
from pygame.sprite import Group
from ship import Ship

class Scoreboard():
"""显示得分信息的类"""

def __init__(self, ai_settings, screen, stats):
self.screen = screen
self.screen_rect = screen.get_rect()
self.ai_settings = ai_settings
self.stats = stats
self.text_color = (50, 50, 50)
self.font = pygame.font.SysFont(None, 48)

# 初始化得分图像
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ships()

def prep_ships(self):
self.ships = Group()
for ship_number in range(self.stats.ships_left):
ship = Ship(self.ai_settings, self.screen)
ship.rect.x = 10 + ship_number * ship.rect.width
ship.rect.y = 10
self.ships.add(ship)

def prep_high_score(self):
high_score = int(round(self.stats.high_score, -1))
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color)
# 将最高得分放在屏幕顶部中央
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top

def prep_level(self):
self.level_image = self.font.render(str(self.stats.level), True, self.text_color, self.ai_settings.bg_color)
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10

def prep_score(self):
"""将得分转化为图像"""
rounded_score = int(round(self.stats.score, -1))
score_str = "{:,}".format(rounded_score)
self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color)
# 将得分放到右上角
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right - 20
self.score_rect.top = 20

def show_score(self):
"""在屏幕上显示得分"""
self.screen.blit(self.score_image, self.score_rect)
self.screen.blit(self.high_score_image, self.high_score_rect)
self.screen.blit(self.level_image, self.level_rect)
# 绘制飞船
self.ships.draw(self.screen)

外星人的 alien.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
def __init__(self, ai_settings, screen):
"""初始化外星人起始位置"""
super(Alien, self).__init__()
self.ai_settings = ai_settings
self.screen = screen

# 加载外星人图像,并设置其 rect 属性
self.image = pygame.image.load("images/alien.bmp")
self.rect = self.image.get_rect()

# 每个外星人都要在屏幕的上面出现
self.rect.x = self.rect.width
self.rect.y = self.rect.height

# 储存每个外星人的位置
self.x = float(self.rect.x)

def blitme(self):
self.screen.blit(self.image, self.rect)

def check_edges(self):
"""如果外星人位于屏幕边缘,就返回 true"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right:
return True
elif self.rect.left <= 0:
return True

def update(self):
"""

向右移动外星人"""
self.x += self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction
self.rect.x = self.x

按钮的 button.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pygame.font

class Button():
def __init__(self, ai_settings, screen, msg):
self.screen = screen
self.screen_rect = screen.get_rect()
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
self.prep_msg(msg)

def prep_msg(self, msg):
self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center

def draw_button(self):
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect)

你可以通过点击以下链接下载附件:

如果你有任何问题或需要进一步的帮助,请随时在评论区发送,我会尽力解答!

python-alien-invasion-game-spaceship

本来这篇文章我已经有思路了,并且其实已经写了一些了,但是因为有一些事情要去做,然后忘记这边还写得文章了,没保存直接关闭了。所以现在是我重新写的了!

最近我是在看《Python从入门到实践》,看的比较快,已经到项目部分了,开始做飞船大战外星人这个基本上入门必学的案例了,但是还是遇到了许多的问题,不过幸好基本上全部解决了了。其实对编程最大的挑战,就是仔细。这个东西确实,有的时候感觉就是控制不住自己,不是多敲了就是少敲了,下面先分析一下会出现什么样的问题。

首先呢其实就是英文大小写问题,还有加不加s,有的时候你前面定义的是有s的,但是后来下面调用的时候忘记了,或者前面没有s,后面加了。

再有就是符号问题,我发现我写Python很爱写分号;,搞得我很难受,用PyCharm一直有波浪线出现。

然后再就是其实真的,一些简单的小程序写上一个文档就好了,文档太多调用很麻烦的!不过说实在的,分的多了,找起来修改很容易,并且其实未来进行编程的时候,大多都不是小程序,还是需要重构一下代码的。不过其实,可以先把想要重构的先写出来,然后再找到合适的地方把它放进去,不是创建一个.py就是创建一个def,反正就是要把它放起来,让主文件空空荡荡最好!

我一般就是错名字,错参数!很难受的,有的找起来非常费劲!

super(Bullet,self).__init__(),比如说这一段,给继承的参数,容易出错。再比如说一些位置,不要理所应当,我今天把左右移动调成上下移动,一开始是我确实以为是up和down,没想到实际上却是top和bottom,虽然有的时候PyCharm没有提示,但是大多数没提示都是错误的。

下面上一下代码,把所有文件放在同一目录下即可,当然图片记得放好或者修改一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 主文件:
import pygame
from setting import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group

def run_game():
# 初始化游戏并且创建一个屏幕对象
pygame.init()
# 初始化背景属性
ai_settings = Settings()
# 使类setting里的内容直接被调用
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("aa") # 窗口名字
# 创建飞船
ship = Ship(ai_settings, screen)
# 创建储存子弹的编组
bullets = Group()
# 开始游戏的主循环
while True:
# 监视鼠标和键盘事件
gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
bullets.update()
gf.update_bullets(bullets)
gf.update_screen(ai_settings, screen, ship, bullets)

run_game()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# game_functions.py
import sys
import pygame
from bullet import Bullet

def check_keydown_events(event, ai_settings, screen, ship, bullets):
"""响应按下"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.key == pygame.K_SPACE:
fire_bullet(ai_settings, screen, ship, bullets)

def fire_bullet(ai_settings, screen, ship, bullets):
# 创建一个子弹并将它加入编组bullets
if len(bullets) < ai_settings.bullet_allowed:
# 判断现存子弹数量是否小于设定值
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)

def check_keyup_events(event, ship):
"""响应松开"""
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False

def check_events(ai_settings, screen, ship, bullets):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, ship, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)

def update_screen(ai_settings, screen, ship, bullets):
"""更新数据"""
screen.fill(ai_settings.bg_color)
# 绘制所有子弹
for bullet in bullets.sprites():
bullet.draw_bullet()
ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()

def update_bullets(bullets):
"""更新子弹位置,删除消失的子弹"""
# 更新子弹位置
bullets.update()
# 删除消失的子弹
for bullet in bullets.copy():
if bullet.rect.bottom < 0:
bullets.remove(bullet)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# ship.py
import pygame

class Ship():
def __init__(self, ai_settings, screen):
"""初始化飞船位置"""
self.screen = screen
self.ai_settings = ai_settings
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load("images/ship.bmp")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# 将每艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 在飞船的属性center中储存小数值
self.center = float(self.rect.centerx)
# 移动标志
self.moving_right = False
self.moving_left = False

def update(self):
"""根据移动标志调整位置"""
# 更新飞船的center值,而不是rect
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
# 根据self.center更新rect对象
self.rect.centerx = self.center

def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# bullet.py
import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
"""一个对飞船发射的子弹进行管理的类"""

def __init__(self, ai_settings, screen, ship):
"""在飞船所处位置创建一个子弹"""
super(Bullet, self).__init__()
self.screen = screen
# 在(0,0)处创建一个表示子弹的矩形,再将位置进行转移(设置成改在的位置)
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
# 储存用小数表示的子弹位置
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor

def update(self):
"""向上移动子弹"""
# 更新子弹位置的小数值
self.y -= self.speed_factor
# 更新子弹的位置
self.rect.y = self.y

def draw_bullet(self):
"""在屏幕上绘制子弹"""
pygame.draw.rect(self.screen, self.color, self.rect)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# setting.py
class Settings():
"""储存外星人大战的所有设置"""

def __init__(self):
"""初始化游戏的设置"""
# 屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 飞船的设置
self.ship_speed_factor = 1.5
# 子弹设置
self.bullet_speed_factor = 1
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullet_allowed = 3

效果图我就不放了,反正还可以吧,就这样!


希望这样的格式更容易阅读和理解你的博客内容。如果有任何其他需要或问题,请随时告诉我。

python 外星人大战,飞船不移动怎么办

今天遇到的小问题!便对着书边敲代码,发现出现错误。python 外星人大战,飞船不移动。这个问题我首先是发去了吾爱,不过后期我自己解决了。如题,边看书边敲的代码,发现飞船不移动。求大佬帮忙看一下!主文件本来发现问题的时候是很慌的,我一开始是以为可能跟书上的内容不太一样,但是后来下了源代码发现确实应该那样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# main.py
import pygame
from setting import Settings
from ship import Ship
import game_functions as gf

def run_game():
# 初始化游戏并且创建一个屏幕对象
pygame.init()

# 初始化背景属性
ai_settings = Settings()

# 使类setting里的内容直接被调用
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion") # 窗口名字

# 创建飞船
ship = Ship(screen)

# 开始游戏的主循环
while True:
# 监视鼠标和键盘事件
gf.check_events(ship)
gf.update_screen(ai_settings, screen, ship)

run_game()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# game_functions.py
import sys
import pygame

def check_events(ship):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT: # 向右移动飞船
ship.rect.centerx += 1
elif event.key == pygame.K_LEFT:
ship.rect.centerx -= 1

def update_screen(ai_settings, screen, ship):
"""更新数据"""
screen.fill(ai_settings.bg_color)
ship.blitme()
pygame.display.flip()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ship.py
import pygame

class Ship():
def __init__(self, screen):
"""初始化飞船位置"""
self.screen = screen

# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load("images/ship.bmp")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()

# 将每艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom

def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ship.py
import pygame

class Ship():
def __init__(self, screen):
"""初始化飞船位置"""
self.screen = screen

# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load("images/ship.bmp")
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()

# 将每艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom

def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)

1
2
3
4
5
6
7
8
9
10
# setting.py
class Settings():
"""储存外星人大战的所有设置"""
def __init__(self):
"""初始化游戏的设置"""
# 屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)

最后还是把书上的内容都复制下来,然后挨个比对,发现错误是game_functions.py文件内第9行if event.type == pygame.K_RIGHT:应该把event.type改为event.key!! 敲代码还是要看仔细,仔细很重要,细节决定成败!