Python爬虫之如何抓取纯静态网站及其资源

news/2024/5/11 4:13:04/文章来源:https://blog.csdn.net/xixi20200/article/details/109485933

遇到的需求

前段时间需要快速做个静态展示页面,要求是响应式和较美观。由于时间较短,自己动手写的话也有点麻烦,所以就打算上网找现成的。

中途找到了几个页面发现不错,然后就开始思考怎么把页面给下载下来。

由于之前还没有了解过爬虫,自然也就没有想到可以用爬虫来抓取网页内容。所以我采取的办法是:

  1. 打开chrome的控制台,进入Application选项

  2. 找到Frames选项,找到html文件,再右键Save As...

  3. 手动创建本地的js/css/images目录

  4. 依次打开Frames选项下的Images/Scripts/Stylesheets,一个文件就要右键Save As...

这个办法是我当时能想到的最好办法了。不过这种人为的办法有以下缺点:

  1. 手工操作,麻烦费时

  2. 一不小心就忘记保存哪个文件

  3. 难以处理路径之间的关系,比如一张图片a.jpg, 它在html中的引用方式是images/banner/a.jpg,这样我们以后还要手动去解决路径依赖关系

然后刚好前段时间接触了一点python,想到可以写个python爬虫来帮我自动抓取静态网站。于是就马上动手,参考相关资料等等。

下面跟大家详细分享一下写爬虫抓取静态网站的全过程。

前置知识储备

在下面的代码实践中,用到了python知识、正则表达式等等,核心技术是正则表达式

我们来一一了解一下。

Python基础知识

如果你之前有过其他语言的学习经历,相信你可以很快上手python这门语言。具体学习可以上查看python官方文档或者其他教程。

爬虫的概念

爬虫,按照我的理解,其实是一段自动执行的计算机程序,在web领域中,它存在的前提是模拟用户在浏览器中的行为。

它的原理就是模拟用户访问web网页,获取网页内容,然后分析网页内容,找出我们感兴趣的部分,并且最后处理数据。

流程图是:

现在流行的爬虫主流实现形式有以下几种:

  1. 自己抓取网页内容,然后自己实现分析过程

  2. 用别人写好的爬虫框架,比如Scrapy

 

正则表达式

 

概念

正则表达式是由一系列元字符和普通字符组成的字符串,它的作用是根据一定的规则来匹配文本,最终可以对文本做出一系列的处理。

元字符是正则表达式中的保留字符,它有特殊的匹配规则,比如*代表匹配0到无穷多次,普通字符就是普通的abcd等等。

比如在前端中,常见的一个操作就是判断用户的输入是否为空,这时候我们可以先通过正则表达式来进行匹配,先过滤掉用户输入的两边空白值,具体实现如下:

 
  1. function trim(value) {

  2.    return value.replace(/^\s+|\s+$/g, '')

  3. }

  4.  
  5. // 输出 => "Python爬虫"

  6. trim(' Python爬虫 ');

下面我们一起来具体了解一下正则表达式中的元字符。

正则表达式中的元字符

在上面,我们说过元字符是正则表达式中的保留字符,它有特殊的匹配规则,所以我们首先要了解经常出现的元字符。

匹配单个字符的元字符

 

  • .代表匹配一个任意字符,除了\n(换行符),比如可以匹配任意的字母数字等等

  • [...]表示字符组,里面可以有任意字符,它只会匹配当中的任意一个,比如[abc]可以匹配abc,这里值得注意的是,字符组里面的元字符有时候会被当成是普通字符,比如[-*?]等等,它代表的仅仅是-*?,而不是-代表区间*代表0到无穷次匹配?代表0或1次匹配

  • [^...][...]的含义相反,它的意思是匹配一个不属于[...]里面的字符,而不是不匹配[...]里面的字符,这两种说法虽然细微但是有很大差别,前者规定一定要匹配一个字符,这个切记。

例子:[^123]可以匹配4/5/6等等,但是不匹配1/2/3

提供计数功能的元字符

 

  • *代表匹配0次到无穷次,可以不匹配任何字符

  • +代表匹配1次到无穷次,至少匹配1次

  • ?代表匹配0次或1次

  • {min, max}代表匹配min次到max次,如a{3, 5}表示a至少匹配3-5次

     

提供位置的元字符

 

  • ^代表匹配字符串开头,如^a表示a要出现在字符串开头,bcd则不匹配

  • $代表匹配字符串结尾, 如A$表示A要出现在字符串结尾,ABAB则不匹配

 

其他元字符

 

  • |代表一个范围,可以匹配任意的子表达式,比如abc|def可以匹配abc或者def,不匹配abd

  • (...)代表分组,它的作用有界定子表达式的范围和与提供功能的元字符相结合,比如(abc|def)+代表可以匹配1次或1次以上的abc或者defdef,如abcabcabc,def

  • \i代表反向引用,i可以为1/2/3等整数,它的含义是指向上一个()里面匹配的内容。比如匹配(abc)+(12)*\1\2,如果匹配成功的话,\1的内容是abc,\2的内容是12或者空。反向引用通常用在匹配""或者''

 

环视

我理解的环视是界定当前匹配子表达式的左边文本和右边文本出现的情况,环视本身不会占据匹配的字符,它是当前子表达式的匹配规则但是本身不算进匹配文本。而我们上面说的元字符都代表一定的规则和占据一定的字符。环视可分为四种:肯定顺序环视、否定顺序环视、肯定逆序环视和否定逆序环视。它们的工作流程如下:

  • 肯定顺序环视:先找到环视中的文本在右侧出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符

  • 否定顺序环视:先找到环视中的文本在右侧没有出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符

  • 肯定逆序环视:先找到环视中的文本在左侧出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符

  • 否定逆序环视:先找到环视中的文本在左侧没有出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符

 

肯定顺序环视

肯定顺序环视匹配成功的条件是当前的子表达式能够匹配右侧文本,它的写法是(?=...),...代表要环视的内容。比如正则表达式(?=hello)he的意思是匹配包含hello的文本,它只匹配位置,不匹配具体字符,匹配到位置之后,才真正匹配要占用的字符是he,所以后面可以具体匹配llo等。

对于(?=hello)he而言,hello world可以匹配成功,而hell world则匹配失败。具体代码如下:

 
  1. import re

  2.  
  3. reg1 = r'(?=hello)he'

  4.  
  5. print(re.search(reg1, 'hello world'))

  6. print(re.search(reg1, 'hell world hello'))

  7. print(re.search(reg1, 'hell world'))

  8.  
  9. # 输出结果

  10. <_sre.SRE_Match object; span=(0, 2), match='he'>

  11. <_sre.SRE_Match object; span=(11, 13), match='he'>

  12. None

 

否定顺序环视

否定顺序环视匹配成功的条件是当前的子表达式不能匹配右侧文本,它的写法是(?!...),...代表要环视的内容,还是上面的例子,比如正则表达式(?!hello)he的意思是匹配不是hello的文本,找到位置,然后匹配he。

例子如下:

 
  1. import re

  2.  
  3. reg2 = r'(?!hello)he'

  4.  
  5. print(re.search(reg2, 'hello world'))

  6. print(re.search(reg2, 'hell world hello'))

  7. print(re.search(reg2, 'hell world'))

  8.  
  9. # 输出结果

  10. None

  11. <_sre.SRE_Match object; span=(0, 2), match='he'>

  12. <_sre.SRE_Match object; span=(0, 2), match='he'>

肯定逆序环视

肯定逆序环视匹配成功的条件是当前的子表达式能够匹配左侧文本,它的写法是(?<=...),...代表要环视的内容,比如正则表达式(?<=hello)-python的意思是匹配包含-python的子表达式,并且它的左侧必须出现hello,hello只匹配位置,不匹配具体字符,真正占用的字符是后面的-python。

例子如下:

 
  1. import re

  2.  
  3. reg3 = r'(?<=hello)-python'

  4. print(re.search(reg3, 'hello-python'))

  5. print(re.search(reg3, 'hell-python hello-python'))

  6. print(re.search(reg3, 'hell-python'))

  7.  
  8. # 输出结果

  9. <_sre.SRE_Match object; span=(5, 12), match='-python'>

  10. <_sre.SRE_Match object; span=(17, 24), match='-python'>

  11. None

否定逆序环视

否定逆序环视匹配成功的条件是当前的子表达式不能匹配左侧文本,它的写法是(?<!...),...代表要环视的内容,比如正则表达式(?<!hello)-python的意思是匹配包含-python的子表达式,并且它的左侧必须不能出现hello。

例子如下:

 
  1. import re

  2.  
  3. reg3 = r'(?<=hello)-python'

  4. print(re.search(reg3, 'hello-python'))

  5. print(re.search(reg3, 'hell-python hello-python'))

  6. print(re.search(reg3, 'hell-python'))

  7.  
  8. # 输出结果

  9. <_sre.SRE_Match object; span=(5, 12), match='-python'>

  10. <_sre.SRE_Match object; span=(17, 24), match='-python'>

  11. None

环视在对字符串插入某些字符很有效,你可以利用它来匹配位置,然后插入对应的字符,而不需要对原来的文本进行替换。

捕获分组

在正则表达式中,分组可以帮助我们提取出想要的特定信息。

指明分组很简单,只需要在想捕获的表达式中两端加上()就可以了。在python中,我们可以用re.search(reg, xx).groups()来获取到所有的分组。
默认的()中都指明了一个分组,分组序号为i,i从1开始,分别用re.search(reg, xx).group(i)来获取。

如果不想捕获分组可以使用(?:...)来指明。

具体例子如下:

 
  1. import re

  2.  
  3. reg7 = r'hello,([a-zA-Z0-9]+)'

  4. print(re.search(reg7, 'hello,world').groups())

  5. print(re.search(reg7, 'hello,world').group(1))

  6. print(re.search(reg7, 'hello,python').groups())

  7. print(re.search(reg7, 'hello,python').group(1))

  8.  
  9. # 输出结果

  10. ('world',)

  11. world

  12. ('python',)

  13. python

 

贪婪匹配

贪婪匹配是指正则表达式尽可能匹配多的字符,也就是趋于最大长度匹配。

正则表达式默认是贪婪模式。

例子如下:

 
  1. import re

  2.  
  3. reg5 = r'hello.*world'

  4. print(re.search(reg5, 'hello world,hello python,hello world,hello javascript'))

  5.  
  6. # 输出结果

  7. <_sre.SRE_Match object; span=(0, 36), match='hello world,hello python,hello world'>

由上可以看到它匹配的是hello world,hello python,hello world而不是刚开始的hello world。那如果我们只是想匹配刚开始的hello world,这时候我们可以利用正则表达式的非贪婪模式。

非贪婪匹配正好与贪婪匹配相反,它是指尽可能匹配少的字符,只要匹配到了就结束。要使用贪婪模式,仅需要在量词后面加上一个问号(?)就可以。

还是刚刚那个例子:

 
  1. import re

  2.  
  3. reg5 = r'hello.*world'

  4. reg6 = r'hello.*?world'

  5. print(re.search(reg5, 'hello world,hello python,hello world,hello javascript'))

  6. print(re.search(reg6, 'hello world,hello python,hello world,hello javascript'))

  7.  
  8. # 输出结果

  9. <_sre.SRE_Match object; span=(0, 36), match='hello world,hello python,hello world'>

  10. <_sre.SRE_Match object; span=(0, 11), match='hello world'>

由上可以看到这是我们刚刚想要匹配的效果。

进入开发

有了上面的基础知识,我们就可以进入开发环节了。

我们想实现的最终效果

本次我们的最终目的是写一个简单的python爬虫,这个爬虫能够下载一个静态网页,并且在保持网页引用资源的相对路径下下载它的静态资源(如js/css/images)。测试网站为http://www.peersafe.cn/index.html,效果图如下:

开发流程

我们的总体思路是先获取到网页的内容,然后利用正则表达式来提取我们想要的资源链接,最后就是下载资源。

获取网页内容

我们选用python3自带的urllib.http来发出http请求,或者你可以采用第三方请求库requests

获取内容的部分代码如下:

 
  1. url = 'http://www.peersafe.cn/index.html'

  2.  
  3. # 读取网页内容

  4. webPage = urllib.request.urlopen(url)

  5. data = webPage.read()

  6. content = data.decode('UTF-8')

  7. print('> 网站内容抓取完毕,内容长度:', len(content))

获取到内容之后,我们需要把它保存下来,也就是写到本地磁盘上。我们定义一个SAVE_PATH路径,代表专门放置爬虫下载的文件。

 
  1. # python-spider-downloads是我们要放置的目录

  2. # 这里推荐使用os模块来获取当前的目录或者拼接路径

  3. # 不推荐直接使用'F://xxx' + '//python-spider-downloads'等方式

  4.  
  5. SAVE_PATH = os.path.join(os.path.abspath('.'), 'python-spider-downloads')

接下来就是为这个站点创建一个单独的文件夹了。这个站点文件夹的格式是xxxx-xx-xx-domain,比如2018-08-03-www.peersafe.cn。在此之前,我们需要写一个函数来提取出一个url链接的域名、相对路径、请求文件名和请求参数等等,这个在后续在根据资源文件的引用方式创建相对应的文件夹时也会用到。

比如输入http://www.peersafe.cn/index.html,那么将会输出:

 
  1. {'baseUrl': 'http://www.peersafe.cn', 'fullPath': 'http://www.peersafe.cn/', 'protocol': 'http://', 'domain

  2. ': 'www.peersafe.cn', 'path': '/', 'fileName': 'index.html', 'ext': 'html', 'params': ''}

部分代码如下:

 
  1. REG_URL = r'^(https?://|//)?((?:[a-zA-Z0-9-_]+\.)+(?:[a-zA-Z0-9-_:]+))((?:/[-_.a-zA-Z0-9]*?)*)((?<=/)[-a-zA-Z0-9]+(?:\.([a-zA-Z0-9]+))+)?((?:\?[a-zA-Z0-9%&=]*)*)$'

  2.  
  3. regUrl = re.compile(REG_URL)

  4.  
  5. # ...

  6.  
  7. '''

  8. 解析URL地址

  9. '''

  10. def parseUrl(url):

  11.    if not url:

  12.        return

  13.  
  14.    res = regUrl.search(url)

  15.    # 在这里,我们把192.168.1.109:8080的形式也解析成域名domain,实际过程中www.baidu.com等才是域名,192.168.1.109只是IP地址

  16.    # ('http://', '192.168.1.109:8080', '/abc/images/111/', 'index.html', 'html', '?a=1&b=2')

  17.    if res is not None:

  18.        path = res.group(3)

  19.        fullPath = res.group(1) + res.group(2) + res.group(3)

  20.  
  21.        if not path.endswith('/'):

  22.            path = path + '/'

  23.            fullPath = fullPath + '/'

  24.        return dict(

  25.            baseUrl=res.group(1) + res.group(2),

  26.            fullPath=fullPath,

  27.            protocol=res.group(1),

  28.            domain=res.group(2),

  29.            path=path,

  30.            fileName=res.group(4),

  31.            ext=res.group(5),

  32.            params=res.group(6)

  33.        )

  34.  
  35. '''

  36. 解析路径

  37.  
  38. eg:

  39.    basePath => F:\Programs\python\python-spider-downloads

  40.    resourcePath => /a/b/c/ or a/b/c

  41.  
  42.    return => F:\Programs\python\python-spider-downloads\a\b\c

  43. '''

  44. def resolvePath(basePath, resourcePath):

  45.    # 解析资源路径

  46.    res = resourcePath.split('/')

  47.    # 去掉空目录 /a/b/c/ => [a, b, c]

  48.    dirList = list(filter(lambda x: x, res))

  49.  
  50.    # 目录不为空

  51.    if dirList:

  52.        # 拼接出绝对路径

  53.        resourcePath = reduce(lambda x, y: os.path.join(x, y), dirList)

  54.        dirStr = os.path.join(basePath, resourcePath)

  55.    else:

  56.        dirStr = basePath

  57.  
  58.    return dirStr

上面的正则表达式REG_URL有点长,这个正则表达式能解析目前我遇到的各种url形式,如果有不能解析的,你可以自行补充,我测试过的url列表可以去我的github中查看。

首先一个最复杂的url链接(比如'http://192.168.1.109:8080/abc/images/111/index.html?a=1&b=2')来说,我们想分别提取出http://192.168.1.109:8080/abc/images/111/index.html?a=1&b=2。提取出/abc/images/111/的目的是为以后创建目录做准备,index.html是写入网页内容的名字。

有需要的可以深入研究一下REG_URL的写法,如果有更好的或者看不懂的,我们可以一起探讨。

有了parseUrl函数之后,我们就可以把刚刚获取网页内容和写入文件联系起来了,代码如下:

 
  1. # 首先创建这个站点的文件夹

  2. urlDict = parseUrl(url)

  3. print('分析的域名:', urlDict)

  4. domain = urlDict['domain']

  5.  
  6. filePath = time.strftime('%Y-%m-%d', time.localtime()) + '-' + domain

  7. # 如果是192.168.1.1:8000等形式,变成192.168.1.1-8000,:不可以出现在文件名中

  8. filePath = re.sub(r':', '-', filePath)

  9. SAVE_PATH = os.path.join(SAVE_PATH, filePath)

  10.  
  11. # 读取网页内容

  12. webPage = urllib.request.urlopen(url)

  13. data = webPage.read()

  14. content = data.decode('UTF-8')

  15. print('> 网站内容抓取完毕,内容长度:', len(content))

  16.  
  17. # 把网站的内容写下来

  18. pageName = ''

  19. if urlDict['fileName'] is None:

  20.    pageName = 'index.html'

  21. else:

  22.    pageName = urlDict['fileName']

  23.  
  24. pageIndexDir = resolvePath(SAVE_PATH, urlDict['path'])

  25. if not os.path.exists(pageIndexDir):

  26.    os.makedirs(pageIndexDir)

  27.  
  28. pageIndexPath = os.path.join(pageIndexDir, pageName)

  29. print('主页的地址:', pageIndexPath)

  30. f = open(pageIndexPath, 'wb')

  31. f.write(data)

  32. f.close()

提取有用的资源链接

我们想要的资源是图片资源,js文件、css文件和字体文件。如果我们要对网页内容一一进行解析,利用分组,来捕获出我们想要的链接形式,比如images/1.pngscripts/lib/jquery.min.js

代码如下:

 
  1. REG_RESOURCE_TYPE = r'(?:href|src|data\-original|data\-src)=["\'](.+?\.(?:js|css|jpg|jpeg|png|gif|svg|ico|ttf|woff2))[a-zA-Z0-9\?\=\.]*["\']'

  2.  
  3. # re.S代表开启多行匹配模式

  4. regResouce = re.compile(REG_RESOURCE_TYPE, re.S)

  5.  
  6. # ...

  7.  
  8. # 解析网页内容,获取有效的链接

  9. # content是上一步读取到的网页内容

  10. contentList = re.split(r'\s+', content)

  11. resourceList = []

  12. for line in contentList:

  13.    resList = regResouce.findall(line)

  14.    if resList is not None:

  15.        resourceList = resourceList + resList

下载资源

在解析出资源链接后,我们要针对每一个资源链接进行检查,把它变成符合http请求的url格式,比如把images/1.png加上http头和刚刚的domain,也就是http://domain/images/1.png

下面是对资源链接进行处理的代码:

 
  1. # ./static/js/index.js

  2. # /static/js/index.js

  3. # static/js/index.js

  4. # //abc.cc/static/js

  5. # http://www.baidu/com/static/index.js

  6. if resourceUrl.startswith('./'):

  7.    resourceUrl = urlDict['fullPath'] + resourceUrl[1:]

  8. elif resourceUrl.startswith('//'):

  9.    resourceUrl = 'https:' + resourceUrl

  10. elif resourceUrl.startswith('/'):

  11.    resourceUrl = urlDict['baseUrl'] + resourceUrl

  12. elif resourceUrl.startswith('http') or resourceUrl.startswith('https'):

  13.    # 不处理,这是我们想要的url格式

  14.    pass

  15. elif not (resourceUrl.startswith('http') or resourceUrl.startswith('https')):

  16.    # static/js/index.js这种情况

  17.    resourceUrl = urlDict['fullPath'] + resourceUrl

  18. else:

  19.    print('> 未知resource url: %s' % resourceUrl)

接着就是对每个规范的资源链接进行解析(parseUrl),提取出它要存放的目录和文件名等等,然后创建对应的目录。

在这里,我也处理了引用的其他网站的资源。

 
  1. # 解析文件,查看文件路径

  2. resourceUrlDict = parseUrl(resourceUrl)

  3. if resourceUrlDict is None:

  4.    print('> 解析文件出错:%s' % resourceUrl)

  5.    continue

  6.  
  7. resourceDomain = resourceUrlDict['domain']

  8. resourcePath = resourceUrlDict['path']

  9. resourceName = resourceUrlDict['fileName']

  10.  
  11. if resourceDomain != domain:

  12.    print('> 该资源不是本网站的,也下载:', resourceDomain)

  13.    # 如果下载的话,根目录就要变了

  14.    # 再创建一个目录,用于保存其他地方的资源

  15.    resourceDomain =  re.sub(r':', '-', resourceDomain)

  16.    savePath = os.path.join(SAVE_PATH, resourceDomain)

  17.    if not os.path.exists(SAVE_PATH):

  18.        print('> 目标目录不存在,创建:', savePath)

  19.        os.makedirs(savePath)

  20.    # continue

  21. else:

  22.    savePath = SAVE_PATH

  23.  
  24. # 解析资源路径

  25. dirStr = resolvePath(savePath, resourcePath)

  26.  
  27. if not os.path.exists(dirStr):

  28.    print('> 目标目录不存在,创建:', dirStr)

  29.    os.makedirs(dirStr)

  30.  
  31. # 写入文件

  32. downloadFile(resourceUrl, os.path.join(dirStr, resourceName))

下载的函数downloadFile的代码是:

 
  1. '''

  2. 下载文件

  3. '''

  4. def downloadFile(srcPath, distPath):

  5.    global downloadedList

  6.  
  7.    if distPath in downloadedList:

  8.        return

  9.    try:

  10.        response = urllib.request.urlopen(srcPath)

  11.        if response is None or response.status != 200:

  12.            return print('> 请求异常:', srcPath)

  13.        data = response.read()

  14.  
  15.        f = open(distPath, 'wb')

  16.        f.write(data)

  17.        f.close()

  18.  
  19.        downloadedList.append(distPath)

  20.        # print('>>>: ' + srcPath + ':下载成功')

  21.  
  22.    except Exception as e:

  23.        print('报错了:', e)

以上就是我们的开发全过程。

知识总结

 

本次开发用到的技术

 

  1. 利用urllib.http来发网络请求

  2. 利用正则表达式来解析资源链接

  3. 利用os系统模块来处理文件路径问题

     

心得体会

这篇文章也算是我这段时间学习python的一个实践总结,顺便记录下正则表达式的知识。同时我也希望能够帮助到那些想学习正则表达式和爬虫的小伙伴。学习资料分享尽在Q裙 467604262

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_837026.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Python爬取网站的图片

爬虫这东西最早出现在我大学计算机网络的课程上面&#xff0c;我们当时的老师人很好&#xff0c;期末不笔试&#xff0c;他说这东西笔试没什么用&#xff0c;对于一个年纪比较大的老师来讲&#xff0c;能提出这种方式&#xff0c;实在难得。当时在考虑做一个与网络有关的东西好…

图片上传使用post_关于规范上传及使用网站图片的通知

由于各委员会在发布文章时没有按规定上传并使用图片&#xff0c;导致上传的图片得不到重复的利用&#xff0c;使工作效率不高&#xff0c;并浪费协会官方平台流量的问题&#xff0c;特发布本通知。请所有工作团队成员在发布新闻时按本通知要求执行。一、上传图片前要求图片在上…

html中怎么写导航栏线框,用CSS美化网站 -- 导航栏和输入框

在上一次用HTML做了一个简单的网站之后&#xff0c;小编决定用CSS来优化网站的结构并且**增添导航栏和输入框最终效果页面修改版大家可以看到在网页的左上方&#xff0c;新增加了导航栏&#xff0c;网页的左下方新增加了输入框。我们将一步一步说明这是如何实现的。导航栏CSS定…

网站云服务器清理,云服务器内存怎么清理

云服务器内存怎么清理 内容精选换一换您可以通过本节内容解决如下问题&#xff1a;用户在管理控制台执行弹性云服务器相关操作后出现异常&#xff0c;针对管理控制台提示的异常信息&#xff0c;应该如何处理&#xff1f;用户参见《弹性云服务器接口参考》调用云服务器相关的API…

网站全局变黑白灰!只需一行代码!

全国性哀悼&#xff0c;很多网站都变为灰色。 到底怎么设置的&#xff1f; 在CSS样式中添加 html {filter: grayscale(100%); } 网上很多资料都是下面这样设置的 html {filter: gray;filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale1);filter: grayscale…

VS“新建网站”与“新建Asp.Net Web 应用程序”的区别

新建网站有两种方法。 1.原来一直用的是直接新建---网站 然后添加后解决方案的项目名称是路径的名称 2.还有一种是新建--项目&#xff0c;然后选web--新建asp.net.web 项目名称是&#xff1a; 新建网站与新建Asp.Net Web 应用程序的区别&#xff1a;VS2010打sp1后&#xff0c;在…

Excel通过网站页面导入数据

选择来自XML数据导入 之后将XML文件改成所有文件就可以看到有.htm的文件&#xff0c;将htm文件打开 在一个HTML页面中选择好表格&#xff0c;之后点击确认&#xff0c;就可以将网页的表格导入Excel

搭建网站速成(1)—hello koa2

强烈安利廖雪峰老师的 koa - 廖雪峰的官方网站 (liaoxuefeng.com) 1.简单的koa2代码 -1.hello koa代码 const Koa require(koa);const app new Koa();app.use(async (ctx, next) > {await next();ctx.response.body "hello koa"; });app.listen(8000); cons…

python爬虫自学网站_Python爬虫学习——获取网页

通过GET请求获取返回的网页&#xff0c;其中加入了User-agent信息&#xff0c;不然会抛出"HTTP Error 403: Forbidden"异常&#xff0c;因为有些网站为了防止这种没有User-agent信息的访问&#xff0c;会验证请求信息中的UserAgent(它的信息包括硬件平台、系统软件、…

搜索引擎更容易识别html,什么样的网站更容易被百度搜索引擎抓取?

搜索引擎友好的网站要具备哪些条件&#xff1f;搜索引擎友好的网站要怎么做呢&#xff1f;要想做好一个让搜索引起喜欢的网站&#xff0c;小编建议你要学会换位思考&#xff0c;从搜索引擎蜘蛛的角度去思考&#xff0c;搜索引擎蜘蛛是如何看待一个网站的页面结构的&#xff1f;…

html怎么转换成app,快速把html、手机网站打包成APP的工具和步骤流程

开心app平台是我们开发的一个打包网站的工具&#xff0c;可以非常方便的把一个手机网站做成APP&#xff0c;也可以直接打包h5代码&#xff0c;免费使用&#xff01;下面介绍使用开心app平台怎么将网站快速打包成APP分七步进行1、注册开心app平台账号2、创建APP、配置基本信息3、…

php网站和asp上传方法,PHP/ASP上传漏洞探究

一、写在前面***这个上传漏洞利用的原理只是针对form格式上传的asp和php脚本***nc(netcat)用于提交数据包dos界面下运行:nc -vv www.***.com 80<1.txt-vv: 回显80: www端口1.txt: 就是你要发送的数据包(更多使用方法请查看本区的帖子)wse(wsockexpert)对本机端口的监视,抓取…

flask专题-小说网站开发一

在比较了诸多python web框架之后&#xff0c;笔者选择选择了flask框架&#xff0c;因为笔者要做推荐系统&#xff0c;收集实验数据&#xff0c;决定开发一个小型网站&#xff0c;收集信息以作后续的推荐系统&#xff0c;对于我来说flask框架完全够用。 网站网址&#xff1a;htt…

flask专题-小说网站开发二(数据准备)

在确定使用flask开发小说网站之后&#xff0c;就要准备数据了&#xff0c;数据是活的灵魂&#xff0c;没有数据就是个空架子&#xff0c;我自己不可能去写小说了&#xff0c;只能从网站采集了&#xff0c;爬虫就是利器&#xff0c;先准备一下小说数据库&#xff0c;以及整个网站…

flask专题-小说网站开发三(注册,登录)

前面几篇准备好了数据库&#xff0c;数据&#xff0c;现在开始往后开发&#xff0c;部分可能与网上他人使用方式不同&#xff0c;本人第一次做&#xff0c;功能都实现了&#xff0c;这一篇开发注册与登录&#xff0c;先贴样式 前端 登录&#xff1a; 注册&#xff1a; 前端样…

flask专题-小说网站开发四(完结)

之前断更了&#xff0c;小说网站改成基于协同过滤的图书推荐系统了&#xff0c;并已经写完&#xff0c;传到gitee了 链接 实现的功能 推荐一块使用协同过滤的思想&#xff0c;计算物品之间的相似度 web框架使用Flask&#xff0c;小说还支持在线看的 主要功能截图 用户基本模…

帝国CMS7.5开发的小说源码自适应网站源码

全网第一版帝国内核CMS7.5开发的小说源码站自适应网站源码 源码介绍 前期没有章节数据 自带采集火车头采集规则 演示地址 演示地址&#xff1a;http://www.txtzn.com

软件工程课程设计-ch小说网站

CH小说网站 [软件开发计划书、需求分析] 作者&#xff1a;陈春旭&#xff0c;习志鹏 目录 1&#xff0e;引言&#xff08;Introduction&#xff09; 4 1.1 背景&#xff08;Background&#xff09; 4 1.2 目的&#xff08;Purpose&#xff09; 4 1.3 范围&#xff08;Scope&am…

HBuilderX打包web网站之wap2app设置底部菜单tabBar

上面是真实案例&#xff0c;首页、在看、我的就是我设置的菜单&#xff0c;还可以设置图标&#xff0c;填写图片网络地址就行。 下面是代码&#xff0c;可以直接用&#xff1a; 第一步&#xff0c;先下载2个文件或者复制也行&#xff0c;那就新建吧: 分别新建一个css文件&am…

小说站源码(带自动采集开源小说网站源码)

小说网站源码是一套文本自动聚合搜索和展示构建系统&#xff0c;设计用于编写由许多较小的文本文档组合而成的小说网站。它使用了受Markdown启发的最小格式语法&#xff0c;并添加了用于注释、概要和交叉引用的元数据语法。它被设计成一个简单的文本编辑器&#xff0c;允许轻松…