精华内容
下载资源
问答
  • 手把手教你利用爬虫爬网页(Python代码)

    万次阅读 多人点赞 2019-05-14 14:34:48
    本文主要分为两部分:部分是网络爬虫的概述,帮助大家详细了解网络爬虫;另部分是HTTP请求的Python实现,帮助大家了解Python中实现HTTP请求的各种方式,以...

    640?wx_fmt=jpeg

    本文主要分为两个部分:一部分是网络爬虫的概述,帮助大家详细了解网络爬虫;另一部分是HTTP请求的Python实现,帮助大家了解Python中实现HTTP请求的各种方式,以便具备编写HTTP网络程序的能力。


    01

    网络爬虫概述


    接下来从网络爬虫的概念、用处与价值和结构等三个方面,让大家对网络爬虫有一个基本的了解。

    1. 网络爬虫及其应用

    随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战,网络爬虫应运而生。网络爬虫(又被称为网页蜘蛛、网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。下面通过图3-1展示一下网络爬虫在互联网中起到的作用:


    640?wx_fmt=png

    ▲图3-1 网络爬虫


    网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫。实际的网络爬虫系统通常是几种爬虫技术相结合实现的。

    搜索引擎(Search Engine),例如传统的通用搜索引擎baidu、Yahoo和Google等,是一种大型复杂的网络爬虫,属于通用性网络爬虫的范畴。但是通用性搜索引擎存在着一定的局限性:

    1. 不同领域、不同背景的用户往往具有不同的检索目的和需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。

    2. 通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。

    3. 万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现和获取。

    4. 通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。

    为了解决上述问题,定向抓取相关网页资源的聚焦爬虫应运而生。

    聚焦爬虫是一个自动下载网页的程序,它根据既定的抓取目标,有选择地访问万维网上的网页与相关的链接,获取所需要的信息。与通用爬虫不同,聚焦爬虫并不追求大的覆盖,而将目标定为抓取与某一特定主题内容相关的网页,为面向主题的用户查询准备数据资源。

    说完了聚焦爬虫,接下来再说一下增量式网络爬虫。增量式网络爬虫是指对已下载网页采取增量式更新和只爬行新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬行的页面是尽可能新的页面。

    和周期性爬行和刷新页面的网络爬虫相比,增量式爬虫只会在需要的时候爬行新产生或发生更新的页面,并不重新下载没有发生变化的页面,可有效减少数据下载量,及时更新已爬行的网页,减小时间和空间上的耗费,但是增加了爬行算法的复杂度和实现难度。

    例如:想获取赶集网的招聘信息,以前爬取过的数据没有必要重复爬取,只需要获取更新的招聘数据,这时候就要用到增量式爬虫。

    最后说一下深层网络爬虫。Web页面按存在方式可以分为表层网页和深层网页。表层网页是指传统搜索引擎可以索引的页面,以超链接可以到达的静态网页为主构成的Web页面。深层网络是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获得的Web页面。

    例如用户登录或者注册才能访问的页面。可以想象这样一个场景:爬取贴吧或者论坛中的数据,必须在用户登录后,有权限的情况下才能获取完整的数据。

    2. 网络爬虫结构

    下面用一个通用的网络爬虫结构来说明网络爬虫的基本工作流程,如图3-4所示。


    640?wx_fmt=png

    ▲图3-4 网络爬虫结构

    网络爬虫的基本工作流程如下:

    1. 首先选取一部分精心挑选的种子URL。

    2. 将这些URL放入待抓取URL队列。

    3. 从待抓取URL队列中读取待抓取队列的URL,解析DNS,并且得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中。此外,将这些URL放进已抓取URL队列。

    4. 分析已抓取URL队列中的URL,从已下载的网页数据中分析出其他URL,并和已抓取的URL进行比较去重,最后将去重过的URL放入待抓取URL队列,从而进入下一个循环。

    02

    HTTP请求的Python实现


    通过上面的网络爬虫结构,我们可以看到读取URL、下载网页是每一个爬虫必备而且关键的功能,这就需要和HTTP请求打交道。接下来讲解Python中实现HTTP请求的三种方式:urllib2/urllib、httplib/urllib以及Requests。

    1. urllib2/urllib实现

    urllib2和urllib是Python中的两个内置模块,要实现HTTP功能,实现方式是以urllib2为主,urllib为辅。

    1.1 首先实现一个完整的请求与响应模型

    urllib2提供一个基础函数urlopen,通过向指定的URL发出请求来获取数据。最简单的形式是:

    
     

    import urllib2
    response=urllib2.urlopen('http://www.zhihu.com')
    html=response.read()
    print html

    其实可以将上面对http://www.zhihu.com的请求响应分为两步,一步是请求,一步是响应,形式如下:

    
     

    import urllib2
    # 请求
    request=urllib2.Request('http://www.zhihu.com')
    # 响应
    response = urllib2.urlopen(request)
    html=response.read()
    print html

    上面这两种形式都是GET请求,接下来演示一下POST请求,其实大同小异,只是增加了请求数据,这时候用到了urllib。示例如下:

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    # info 需要被编码为urllib2能理解的格式,这里用到的是urllib
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    html = response.read()

    但是有时会出现这种情况:即使POST请求的数据是对的,但是服务器拒绝你的访问。这是为什么呢?问题出在请求中的头信息,服务器会检验请求头,来判断是否是来自浏览器的访问,这也是反爬虫的常用手段。

    1.2 请求头headers处理

    将上面的例子改写一下,加上请求头信息,设置一下请求头中的User-Agent域和Referer域信息。

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    referer='http://www.xxxxxx.com/'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    # 将user_agent,referer写入头信息
    headers={'User-Agent':user_agent,'Referer':referer}
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url, data,headers)
    response = urllib2.urlopen(req)
    html = response.read()

    也可以这样写,使用add_header来添加请求头信息,修改如下:

    
     

    import urllib
    import urllib2
    url = 'http://www.xxxxxx.com/login'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    referer='http://www.xxxxxx.com/'
    postdata = {'username' : 'qiye',
        'password' : 'qiye_pass'}
    data = urllib.urlencode(postdata)
    req = urllib2.Request(url)
    # 将user_agent,referer写入头信息
    req.add_header('User-Agent',user_agent)
    req.add_header('Referer',referer)
    req.add_data(data)
    response = urllib2.urlopen(req)
    html = response.read()

    对有些header要特别留意,服务器会针对这些header做检查,例如:

    • User-Agent:有些服务器或Proxy会通过该值来判断是否是浏览器发出的请求。

    • Content-Type:在使用REST接口时,服务器会检查该值,用来确定HTTP Body中的内容该怎样解析。在使用服务器提供的RESTful或SOAP服务时,Content-Type设置错误会导致服务器拒绝服务。常见的取值有:application/xml(在XML RPC,如RESTful/SOAP调用时使用)、application/json(在JSON RPC调用时使用)、application/x-www-form-urlencoded(浏览器提交Web表单时使用)。

    • Referer:服务器有时候会检查防盗链。

    1.3 Cookie处理

    urllib2对Cookie的处理也是自动的,使用CookieJar函数进行Cookie的管理。如果需要得到某个Cookie项的值,可以这么做:

    
     

    import urllib2
    import cookielib
    cookie = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
    response = opener.open('http://www.zhihu.com')
    for item in cookie:
        print item.name+':'+item.value

    但是有时候会遇到这种情况,我们不想让urllib2自动处理,我们想自己添加Cookie的内容,可以通过设置请求头中的Cookie域来做:

    
     

    import  urllib2
    opener = urllib2.build_opener()
    opener.addheaders.append( ( 'Cookie''email=' + "xxxxxxx@163.com" ) )
    req = urllib2.Request( "http://www.zhihu.com/" )
    response = opener.open(req)
    print response.headers
    retdata = response.read()

    1.4 Timeout设置超时

    在Python2.6之前的版本,urllib2的API并没有暴露Timeout的设置,要设置Timeout值,只能更改Socket的全局Timeout值。示例如下:

    
     

    import urllib2
    import socket
    socket.setdefaulttimeout(10# 10 秒钟后超时
    urllib2.socket.setdefaulttimeout(10# 另一种方式

    在Python2.6及新的版本中,urlopen函数提供了对Timeout的设置,示例如下:

    
     

    import urllib2
    request=urllib2.Request('http://www.zhihu.com')
    response = urllib2.urlopen(request,timeout=2)
    html=response.read()
    print html

    1.5 获取HTTP响应码

    对于200 OK来说,只要使用urlopen返回的response对象的getcode()方法就可以得到HTTP的返回码。但对其他返回码来说,urlopen会抛出异常。这时候,就要检查异常对象的code属性了,示例如下:

    
     

    import urllib2
    try:
        response = urllib2.urlopen('http://www.google.com')
        print response
    except urllib2.HTTPError as e:
        if hasattr(e, 'code'):
            print 'Error code:',e.code

    1.6 重定向

    urllib2默认情况下会针对HTTP 3XX返回码自动进行重定向动作。要检测是否发生了重定向动作,只要检查一下Response的URL和Request的URL是否一致就可以了,示例如下:

    
     

    import urllib2
    response = urllib2.urlopen('http://www.zhihu.cn')
    isRedirected = response.geturl() == 'http://www.zhihu.cn'

    如果不想自动重定向,可以自定义HTTPRedirectHandler类,示例如下:

    
     

    import urllib2
    class RedirectHandler(urllib2.HTTPRedirectHandler):
        def http_error_301(self, req, fp, code, msg, headers):
            pass
        def http_error_302(self, req, fp, code, msg, headers):
            result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, 
            msg, headers)
            result.status = code
            result.newurl = result.geturl()
            return result
    opener = urllib2.build_opener(RedirectHandler)
    opener.open('http://www.zhihu.cn')

    1.7 Proxy的设置

    在做爬虫开发中,必不可少地会用到代理。urllib2默认会使用环境变量http_proxy来设置HTTP Proxy。但是我们一般不采用这种方式,而是使用ProxyHandler在程序中动态设置代理,示例代码如下:

    
     

    import urllib2
    proxy = urllib2.ProxyHandler({'http''127.0.0.1:8087'})
    opener = urllib2.build_opener([proxy,])
    urllib2.install_opener(opener)
    response = urllib2.urlopen('http://www.zhihu.com/')
    print response.read()

    这里要注意的一个细节,使用urllib2.install_opener()会设置urllib2的全局opener,之后所有的HTTP访问都会使用这个代理。这样使用会很方便,但不能做更细粒度的控制,比如想在程序中使用两个不同的Proxy设置,这种场景在爬虫中很常见。比较好的做法是不使用install_opener去更改全局的设置,而只是直接调用opener的open方法代替全局的urlopen方法,修改如下:

    
     

    import urllib2
    proxy = urllib2.ProxyHandler({'http''127.0.0.1:8087'})
    opener = urllib2.build_opener(proxy,)
    response = opener.open("http://www.zhihu.com/")
    print response.read()


    2. httplib/urllib实现

    httplib模块是一个底层基础模块,可以看到建立HTTP请求的每一步,但是实现的功能比较少,正常情况下比较少用到。在Python爬虫开发中基本上用不到,所以在此只是进行一下知识普及。下面介绍一下常用的对象和函数:


    • 创建HTTPConnection对象:

      class httplib.HTTPConnection(host[, port[, strict[, timeout[, source_address]]]])。

    • 发送请求:

      HTTPConnection.request(method, url[, body[, headers]])。

    • 获得响应:

      HTTPConnection.getresponse()。

    • 读取响应信息:

      HTTPResponse.read([amt])。

    • 获得指定头信息:

      HTTPResponse.getheader(name[, default])。

    • 获得响应头(header, value)元组的列表:

      HTTPResponse.getheaders()。

    • 获得底层socket文件描述符:

      HTTPResponse.fileno()。

    • 获得头内容:

      HTTPResponse.msg。

    • 获得头http版本:

      HTTPResponse.version。

    • 获得返回状态码:

      HTTPResponse.status。

    • 获得返回说明:

      HTTPResponse.reason。

    接下来演示一下GET请求和POST请求的发送,首先是GET请求的示例,如下所示:

    
     

    import httplib
    conn =None
    try:
        conn = httplib.HTTPConnection("www.zhihu.com")
        conn.request("GET""/")
        response = conn.getresponse()
        print response.status, response.reason
        print '-' * 40
        headers = response.getheaders()
        for h in headers:
            print h
        print '-' * 40
        print response.msg
    except Exception,e:
        print e
    finally:
        if conn:
            conn.close()

    POST请求的示例如下:

    
     

    import httplib, urllib
    conn = None
    try:
        params = urllib.urlencode({'name''qiye''age'22})
        headers = {"Content-type""application/x-www-form-urlencoded"
        , "Accept""text/plain"}
        conn = httplib.HTTPConnection("www.zhihu.com"80, timeout=3)
        conn.request("POST""/login", params, headers)
        response = conn.getresponse()
        print response.getheaders() # 获取头信息
        print response.status
        print response.read()
    except Exception, e:
        print e
        finally:
        if conn:
            conn.close()

    3. 更人性化的Requests

    Python中Requests实现HTTP请求的方式,是本人极力推荐的,也是在Python爬虫开发中最为常用的方式。Requests实现HTTP请求非常简单,操作更加人性化。

    Requests库是第三方模块,需要额外进行安装。Requests是一个开源库,源码位于:

    GitHub: https://github.com/kennethreitz/requests

    希望大家多多支持作者。

    使用Requests库需要先进行安装,一般有两种安装方式:

    • 使用pip进行安装,安装命令为:pip install requests,不过可能不是最新版。

    • 直接到GitHub上下载Requests的源代码,下载链接为:

      https://github.com/kennethreitz/requests/releases

      将源代码压缩包进行解压,然后进入解压后的文件夹,运行setup.py文件即可。

    如何验证Requests模块安装是否成功呢?在Python的shell中输入import requests,如果不报错,则是安装成功。如图3-5所示。

    640?wx_fmt=png

    ▲图3-5 验证Requests安装

    3.1 首先还是实现一个完整的请求与响应模型

    以GET请求为例,最简单的形式如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print r.content

    大家可以看到比urllib2实现方式的代码量少。接下来演示一下POST请求,同样是非常简短,更加具有Python风格。示例如下:

    
     

    import requests
    postdata={'key':'value'}
    r = requests.post('http://www.xxxxxx.com/login',data=postdata)
    print r.content

    HTTP中的其他请求方式也可以用Requests来实现,示例如下:

    
     

    r = requests.put('http://www.xxxxxx.com/put', data = {'key':'value'})
    r = requests.delete('http://www.xxxxxx.com/delete')
    r = requests.head('http://www.xxxxxx.com/get')
    r = requests.options('http://www.xxxxxx.com/get')

    接着讲解一下稍微复杂的方式,大家肯定见过类似这样的URL:

    http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

    就是在网址后面紧跟着“?”,“?”后面还有参数。那么这样的GET请求该如何发送呢?肯定有人会说,直接将完整的URL带入即可,不过Requests还提供了其他方式,示例如下:

    
     

    import requests
        payload = {'Keywords''blog:qiyeboy','pageindex':1}
    r = requests.get('http://zzk.cnblogs.com/s/blogpost', params=payload)
    print r.url

    通过打印结果,我们看到最终的URL变成了:

    http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

    3.2 响应与编码

    还是从代码入手,示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print 'content-->'+r.content
    print 'text-->'+r.text
    print 'encoding-->'+r.encoding
    r.encoding='utf-8'
    print 'new text-->'+r.text

    其中r.content返回的是字节形式,r.text返回的是文本形式,r.encoding返回的是根据HTTP头猜测的网页编码格式。

    输出结果中:“text-->”之后的内容在控制台看到的是乱码,“encoding-->”之后的内容是ISO-8859-1(实际上的编码格式是UTF-8),由于Requests猜测编码错误,导致解析文本出现了乱码。Requests提供了解决方案,可以自行设置编码格式,r.encoding='utf-8'设置成UTF-8之后,“new text-->”的内容就不会出现乱码。

    但是这种手动的方式略显笨拙,下面提供一种更加简便的方式:chardet,这是一个非常优秀的字符串/文件编码检测模块。安装方式如下:

    
     

    pip install chardet

    安装完成后,使用chardet.detect()返回字典,其中confidence是检测精确度,encoding是编码形式。示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    print chardet.detect(r.content)
    r.encoding = chardet.detect(r.content)['encoding']
    print r.text

    直接将chardet探测到的编码,赋给r.encoding实现解码,r.text输出就不会有乱码了。

    除了上面那种直接获取全部响应的方式,还有一种流模式,示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com',stream=True)
    print r.raw.read(10)

    设置stream=True标志位,使响应以字节流方式进行读取,r.raw.read函数指定读取的字节数。

    3.3 请求头headers处理

    Requests对headers的处理和urllib2非常相似,在Requests的get函数中添加headers参数即可。示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    r = requests.get('http://www.baidu.com',headers=headers)
    print r.content

    3.4 响应码code和响应头headers处理

    获取响应码是使用Requests中的status_code字段,获取响应头使用Requests中的headers字段。示例如下:

    
     

    import requests
    r = requests.get('http://www.baidu.com')
    if r.status_code == requests.codes.ok:
        print r.status_code# 响应码
        print r.headers# 响应头
        print r.headers.get('content-type')# 推荐使用这种获取方式,获取其中的某个字段
        print r.headers['content-type']# 不推荐使用这种获取方式
    else:
        r.raise_for_status()

    上述程序中,r.headers包含所有的响应头信息,可以通过get函数获取其中的某一个字段,也可以通过字典引用的方式获取字典值,但是不推荐,因为如果字段中没有这个字段,第二种方式会抛出异常,第一种方式会返回None。

    r.raise_for_status()是用来主动地产生一个异常,当响应码是4XX或5XX时,raise_for_status()函数会抛出异常,而响应码为200时,raise_for_status()函数返回None。

    3.5 Cookie处理

    如果响应中包含Cookie的值,可以如下方式获取Cookie字段的值,示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    r = requests.get('http://www.baidu.com',headers=headers)
    # 遍历出所有的cookie字段的值
    for cookie in r.cookies.keys():
        print cookie+':'+r.cookies.get(cookie)

    如果想自定义Cookie值发送出去,可以使用以下方式,示例如下:

    
     

    import requests
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers={'User-Agent':user_agent}
    cookies = dict(name='qiye',age='10')
    r = requests.get('http://www.baidu.com',headers=headers,cookies=cookies)
    print r.text

    还有一种更加高级,且能自动处理Cookie的方式,有时候我们不需要关心Cookie值是多少,只是希望每次访问的时候,程序自动把Cookie的值带上,像浏览器一样。Requests提供了一个session的概念,在连续访问网页,处理登录跳转时特别方便,不需要关注具体细节。使用方法示例如下:

    
     

    import Requests
    oginUrl = 'http://www.xxxxxxx.com/login'
    s = requests.Session()
    #首先访问登录界面,作为游客,服务器会先分配一个cookie
    r = s.get(loginUrl,allow_redirects=True)
    datas={'name':'qiye','passwd':'qiye'}
    #向登录链接发送post请求,验证成功,游客权限转为会员权限
    r = s.post(loginUrl, data=datas,allow_redirects= True)
    print r.text

    上面的这段程序,其实是正式做Python开发中遇到的问题,如果没有第一步访问登录的页面,而是直接向登录链接发送Post请求,系统会把你当做非法用户,因为访问登录界面时会分配一个Cookie,需要将这个Cookie在发送Post请求时带上,这种使用Session函数处理Cookie的方式之后会很常用。

    3.6 重定向与历史信息

    处理重定向只是需要设置一下allow_redirects字段即可,例如:

    r=requests.get('http://www.baidu.com',allow_redirects=True)

    将allow_redirects设置为True,则是允许重定向;设置为False,则是禁止重定向。如果是允许重定向,可以通过r.history字段查看历史信息,即访问成功之前的所有请求跳转信息。示例如下:

    
     

    import requests
    r = requests.get('http://github.com')
    print r.url
    print r.status_code
    print r.history

    打印结果如下:

    
     

    https://github.com/
    200
    (<Response [301]>,)

    上面的示例代码显示的效果是访问GitHub网址时,会将所有的HTTP请求全部重定向为HTTPS。

    3.7 超时设置

    超时选项是通过参数timeout来进行设置的,示例如下:

    
     

    requests.get('http://github.com', timeout=2)

    3.8 代理设置

    使用代理Proxy,你可以为任意请求方法通过设置proxies参数来配置单个请求:

    
     

    import requests
    proxies = {
        "http""http://0.10.1.10:3128",
        "https""http://10.10.1.10:1080",
    }
    requests.get("http://example.org", proxies=proxies)

    也可以通过环境变量HTTP_PROXY和HTTPS_PROXY?来配置代理,但是在爬虫开发中不常用。你的代理需要使用HTTP Basic Auth,可以使用http://user:password@host/语法:

    
     

    proxies = {
        "http""http://user:pass@10.10.1.10:3128/",
    }


    03

    小结


    本文主要讲解了网络爬虫的结构和应用,以及Python实现HTTP请求的几种方法。希望大家对本文中的网络爬虫工作流程和Requests实现HTTP请求的方式重点吸收消化。

    本文摘编自《Python爬虫开发与项目实战》,经出版方授权发布。

    关于作者:范传辉,资深网虫,Python开发者,参与开发了多项网络应用,在实际开发中积累了丰富的实战经验,并善于总结,贡献了多篇技术文章广受好评。研究兴趣是网络安全、爬虫技术、数据分析、驱动开发等技术。

    640?wx_fmt=jpeg

    Python爬虫开发与项目实战

    扫码购买

    640?wx_fmt=png


    本书特色:

    • 由浅入深,从Python和Web前端基础开始讲起,逐步加深难度,层层递进。

    • 内容详实,从静态网站到动态网站,从单机爬虫到分布式爬虫,既包含基础知识点,又讲解了关键问题和难点分析,方便读者完成进阶。

    • 实用性强,本书共有9个爬虫项目,以系统的实战项目为驱动,由浅及深地讲解爬虫开发中所需的知识和技能。

    • 难点详析,对js加密的分析、反爬虫措施的突破、去重方案的设计、分布式爬虫的开发进行了细致的讲解。

    扫码购买

    640?wx_fmt=png

    展开全文
  • python flask web开发入门与项目实战

    千人学习 2019-12-15 19:02:04
            Web网站发展至今,特别是服务器... 综上所述,Flask 是一个用Python语言编写的Web微框架,可以让开发人员快速开发各种Web应用        课程预计每周更新两节
  • 浏览网页,打开网页上网,网络协议

    系统环境:

    OS:Linux ubuntu 2.6.32-46-generic #105-Ubuntu SMP Fri Mar 1 00:08:49 UTC 2013 i686 GNU/Linux
    抓包软件:Wireshark (sudo wireshark ,普通用户权限不够 )

    网络环境

    一个TP-link无线路由器,与PC一台,PC—-TP-link——internet

    按照抓包的时间顺序 ,先列出协议,然后再分开介绍

    1. EAPOL

    2. SSDP

    3. ARP

    4. DHCP

    5. IGMP

    6. MDNS

    7. DNS

    8. ICMPV6

    9. TCP

    10. HTTP

    11. SSL

    12. TLSv1

    13. OCSP

    EAPOL是EAP over LAN,使EAP协议也能够在广播式的以太网中使用。EAP是在RFC 3748中定义的一种认证协议,该协议用于在PPP等点到点网络中的认证,可支持多种认证机制。在802.1X中对EAP进行了简单的修改形成了EAPOL。EAP工作在OSI模型的第二层上,不需要用户端事先获取IP地址,简单易实现,主要用于客户端和认证者之间的认证信息交互。
    

    802.1x认证的EAP协议(总体流程)

    Supplicant主机 服务器
    ———- ————-
    |——————————>| 主机向服务器(多播或广播地址)发送EAPOL-Start
    | 1. EAPOL-Start |
    | |
    |<——————————| 要求验证身份的请求
    | 2. EAP-REQUEST-Identity |
    | |
    |——————————>| 回应(用户名)
    | 3. EAP-RESPONSE-Identity |
    | |
    |<——————————| 要求验证密码的MD5校验值(随机加密字Challenge)
    | 4. EAP-REQUEST-MD5_Challenge |
    | |
    |——————————>| 回应(使用Challenge加密口令)
    | 5. EAP-RESPONSE-MD5_Challenge |
    | |
    |<——————————| EAP-Success(判断正确性)
    | 6. EAP-Success |
    | |
    在任何时候服务器发来EAP-Failure数据包,都表示整个认证过程终止。

    展开全文
  • 本文转自公众号:猿人学Python摘要:介绍爬取大量网页需要重点关注的几个方面。通常来说,多数人写的爬虫量级很小,几千上万个页面/信息,多则也不过百万以内。对一个网站定向...
    
     

    本文转自公众号:猿人学Python

    摘要:介绍爬取大量网页需要重点关注的几个方面。

    通常来说,多数人写的爬虫量级很小,几千上万个页面/信息,多则也不过百万以内。对一个网站定向抓取几十万张页面一般只用解决访问频率限制问题就好。对机器内存,硬盘空间,URL去重,网络性能,抓取间隙时间调优一般都不会在意。如果要设计一个单台每天抓取上百万张网页,共有一亿张页面的网站时,访问频率限制问题就不是最棘手的问题了,上述每一项都要很好解决才行。硬盘存储,内存,网络性能等问题我们一项项来拆解。

    本篇只关注如何让爬虫的抓取性能最大化上,没有使用scrapy等爬虫框架,就是多线程+Python requests库搞定。

    优化硬盘存储

    所以千万级网页的抓取是需要先设计的,先来做一个计算题。共要抓取一亿张页面,一般一张网页的大小是400KB左右,一亿张网页就是1亿X200KB=36TB 。这么大的存储需求,一般的电脑和硬盘都是没法存储的。所以肯定要对网页做压缩后存储,可以用zlib压缩,也可以用压缩率更好的bz2或pylzma 。

    但是这样还不够,我们拿天眼查的网页来举例。天眼查一张公司详情页的大小是700KB 。

    640?wx_fmt=png
    img

    对这张网页zlib压缩后是100KB。

    640?wx_fmt=png
    img

    一亿个100KB(9TB)还是太大,要对网页特殊处理一下,可以把网页的头和尾都去掉,只要body部分再压缩。因为一张html页面里和

    大都是公共的头尾信息和js/css代码,对你以后做正文内容抽取不会影响(也可以以后做内容抽取时把头尾信息补回去就好)。


    来看一下去掉头尾后的html页面大小是300KB,压缩后是47KB。

    640?wx_fmt=png
    img

    一亿张就是4T,差不多算是能接受了。京东上一个4T硬盘600多元。

    优化内存,URL去重

    再来说内存占用问题,做爬虫程序为了防止重复抓取URL,一般要把URL都加载进内存里,放在set()里面。拿天眼查的URL举例:

    https://www.tianyancha.com/company/23402373

    这个完整URL有44个字节,一亿个URL就是4G,一亿个URL就要占用4G内存,这还没有算存这一亿个URL需要的数据结构内存,还有待抓取URL,已抓取URL还保存在内存中的html等等消耗的内存。

    所以这样直接用set()保存URL是不建议的,除非你的内存有十几个G。

    一个取巧的办法是截断URL。只把URL:

    https://www.tianyancha.com/company/23402373

    的后缀:23402373放进set()里,23402373只占8个字节,一亿个URL占700多M内存。

    但是如果你是用的野云主机,用来不断拨号用的非正规云主机,这700多M内存也是吃不消的,机器会非常卡。

    就还需要想办法压缩URL的内存占用,可以使用BloomFilter算法,是一个很经典的算法,非常适用海量数据的排重过滤,占用极少的内存,查询效率也非常的高。它的原理是把一个字符串映射到一个bit上,刚才23402373占8个字节,现在只占用1个bit(1字节=8bit),内存节省了近64倍,以前700M内存,现在只需要10多M了。

    BloomFilter调用也非常简单,当然需要先install 安装bloom_filter:

    1from bloom_filter import BloomFilter# 生成一个装1亿大小的bloombloom = BloomFilter(max_elements=100000000, error_rate=0.1)# 向bloom添加URLbloom.add('https://www.tianyancha.com/company/23402373')#判断URL是否在bloombloom.__contains__('https://www.tianyancha.com/company/23402373')from bloom_filter import BloomFilter# 生成一个装1亿大小的bloombloom = BloomFilter(max_elements=100000000, error_rate=0.1)# 向bloom添加URLbloom.add('https://www.tianyancha.com/company/23402373')#判断URL是否在bloombloom.__contains__('https://www.tianyancha.com/company/23402373')

    不过奇怪,bloom里没有公有方法来判断URL是否重复,我用的contains()方法,也可能是我没用对,不过判重效果是一样的。

    反抓取访问频率限制

    单台机器,单个IP大家都明白,短时间内访问一个网站几十次后肯定会被屏蔽的。每个网站对IP的解封策略也不一样,有的1小时候后又能重新访问,有的要一天,有的要几个月去了。突破抓取频率限制有两种方式,一种是研究网站的反爬策略。有的网站不对列表页做频率控制,只对详情页控制。有的针对特定UA,referer,或者微信的H5页面的频率控制要弱很多。我在这两篇文章有讲到《爬虫小偏方:绕开登陆和访问频率控制》《 爬虫小偏方二:修改referer后可以不用登录了》。

    另一种方式就是多IP抓取,多IP抓取又分IP代理池和adsl拨号两种,我这里说adsl拨号的方式,IP代理池相对于adsl来说,我觉得收费太贵了。要稳定大规模抓取肯定是要用付费的,一个月也就100多块钱。

    adsl的特点是可以短时间内重新拨号切换IP,IP被禁止了重新拨号一下就可以了。这样你就可以开足马力疯狂抓取了,但是一天只有24小时合86400秒,要如何一天抓过百万网页,让网络性能最大化也是需要下一些功夫的,后面我再详说。

    至于有哪些可以adsl拨号的野云主机,你在百度搜"vps adsl",能选择的厂商很多的。大多宣称有百万级IP资源可拨号,我曾测试过一段时间,把每次拨号的IP记录下来,有真实二三十万IP的就算不错了。

    选adsl的一个注意事项是,有的厂商拨号IP只能播出C段和D段IP,110(A段).132(B段).3(C段).2(D段),A和B段都不会变,靠C,D段IP高频次抓取对方网站,有可能对方网站把整个C/D段IP都封掉。

    C/D段加一起255X255就是6万多个IP全都报废,所以要选拨号IP范围较宽的厂商。 你要问我哪家好,我也不知道,这些都是野云主机,质量和稳定性本就没那么好。只有多试一试,试的成本也不大,买一台玩玩一个月也就一百多元,还可以按天买。

    为什么不用付费IP代理池?

    因为比adsl拨号贵很多,因为全速抓取时,一个反爬做得可以的网站10秒内就会封掉这个IP,所以10秒就要换一个IP,理想状况下一天86400秒,要换8640个IP。

    如果用付费IP代理池的话,一个代理IP收费4分钱,8640个IP一天就要345元。 adsl拨号的主机一个月才100多元。

    adsl拨号Python代码

    怎么拨号厂商都会提供的,建议是用厂商提供的方式,这里只是示例:

    windows下用os调用rasdial拨号:

    1import os# 拨号断开os.popen('rasdial 网络链接名称 /disconnect')# 拨号os.popen('rasdial 网络链接名称 adsl账号 adsl密码')import os# 拨号断开os.popen('rasdial 网络链接名称 /disconnect')# 拨号os.popen('rasdial 网络链接名称 adsl账号 adsl密码')

    linux下拨号:

    1import os# 拨号断开code = os.system('ifdown 网络链接名称')# 拨号code = os.system('ifup 网络链接名称')import os# 拨号断开code = os.system('ifdown 网络链接名称')# 拨号code = os.system('ifup 网络链接名称')

    网络性能,抓取技术细节调优

    上面步骤做完了,每天能达到抓取五万网页的样子,要达到百万级规模,还需把网络性能和抓取技术细节调优。

    1.调试开多少个线程,多长时间拨号切换IP一次最优

    每个网站对短时间内访问次数的屏蔽策略不一样,这需要实际测试,找出抓取效率最大化的时间点。先开一个线程,一直抓取到IP被屏蔽,记录下抓取耗时,总抓取次数,和成功抓取次数。 再开2个线程,重复上面步骤,记录抓取耗时,总的和成功的抓取次数。再开4个线程,重复上面步骤。整理成一个表格如下,下图是我抓天眼查时,统计抓取极限和细节调优的表格:

    640?wx_fmt=png
    img

    从上图比较可以看出,当有6个线程时,是比较好的情况。耗时6秒,成功抓取80-110次。虽然8个线程只耗时4秒,但是成功抓取次数已经在下降了。所以线程数可以设定为开6个。

    开多少个线程调试出来了,那多久拨号一次呢?

    从上面的图片看到,貌似每隔6秒拨号是一个不错的选择。可以这样做,但是我选了另一个度量单位,就是每总抓取120次就重新拨号。为什么这样选呢?从上图也能看到,基本抓到120次左右就会被屏蔽,每隔6秒拨号其实误差比较大,因为网络延迟等各种问题,导致6秒内可能抓100次,也可能抓120次。

    2.requests请求优化

    要优化requests.get(timeout=1.5)的超时时间,不设置超时的话,有可能get()请求会一直挂起等待。而且野云主机本身性能就不稳定,长时间不回请求很正常。如果要追求抓取效率,超时时间设置短一点,设置10秒超时完全没有意义。对于超时请求失败的,大不了以后再二次请求,也比设置10秒的抓取效率高很多。

    3.优化adsl拨号等待时间

    上面步骤已算把单台机器的抓取技术问题优化到一个高度了,还剩一个优化野云主机的问题。就是每次断开拨号后,要等待几秒钟再拨号,太短时间内再拨号有可能又拨到上一个IP,还有可能拨号失败,所以要等待6秒钟(测试值)。所以要把拨号代码改一下:

    1import os# 断开拨号os.popen('rasdial 网络名称 /disconnect')time.sleep(6)# 拨号os.popen('rasdial 网络名称 adsl账号名 adsl密码')import os# 断开拨号os.popen('rasdial 网络名称 /disconnect')time.sleep(6)# 拨号os.popen('rasdial 网络名称 adsl账号名 adsl密码')

    而且 os.popen('rasdial 网络名称 adsl账号名 adsl密码') 拨号完成后,你还不能马上使用,那时外网还是不可用的,你需要检测一下外网是否联通。

    我使用 ping 功能来检测外网连通性:

    1import os code = os.system('ping www.baidu.com')import os code = os.system('ping www.baidu.com')

    code为0时表示联通,不为0时还要重新拨号。而ping也很耗时间的,一个ping命令会ping 4次,就要耗时4秒。

    640?wx_fmt=png
    img

    上面拨号等待6秒加上 ping 的4秒,消耗了10秒钟。上面猿人学Python说了,抓120次才用6秒,每拨号一次要消耗10秒,而且是每抓120次就要重拨号,想下这个时间太可惜了,每天8万多秒有一半时间都消耗在拨号上面了,但是也没办法。

    当然好点的野云主机,除了上面说的IP范围的差异,就是拨号质量差异。好的拨号等待时间更短一点,拨号出错的概率要小一点。

    通过上面我们可以轻松计算出一组抓取的耗时是6秒,拨号耗时10秒,总耗时16秒。一天86400秒,就是5400组抓取,上面说了一组抓取是120次。一天就可以抓取5400X120=64万张网页。

    按照上述的设计就可以做到一天抓60多万张页面,如果你把adsl拨号耗时再优化一点,每次再节约2-3秒,就趋近于百万抓取量级了。

    另外野云主机一个月才100多,很便宜,所以你可以再开一台adsl拨号主机,用两台一起抓取,一天就能抓一百多万张网页。几天时间就能镜像一个过千万网页的网站。

    知识Tips:

    1.为什么不用异步抓取?

    没必要,这里的整个抓取关键是网络性能,而不是程序性能。用异步把程序性能提高了,单位时间的抓取次数是提高了,但是这样反而会击中对方网站的访问频率控制策略。

    2.要计算对方的带宽压力,不要抓取太过分了

    抓取归抓取,但不要影响对方网站,把对方网站带宽都打满了。

    一个中小型网站的带宽在5M以内,大一点的网站带宽可能10-30M,超大型的另算。

    一张网页300KB,对方一般会压缩后传输给浏览器,就按压缩后30KB算,你的爬虫一秒请求20次,带宽就是600KB。可能一个网站每天都有几十个爬虫都在爬,我们按有10个爬虫在同时抓取,就是这些爬虫一秒内就要消耗600KBX10=6M带宽。

    再加上还有正规爬虫,人家网站上的正常用户访问这些,算下来可能一共要消耗10M带宽。一般的大中型网站都是吃不消的。

    本文完。

    展开全文
  • 教你写一个简单的网页(html网页开发入门)

    万次阅读 多人点赞 2017-10-16 15:02:49
    网页的样式(美化网页最重要的块) JavaScript  网页的交互效果,比如对用户鼠标事件作出响应 HTML 什么是HTML HTML的全称是HyperTextMarkupLanguage,超文本标记语言  其实它就是文本,由浏览器...

    网页的组成

    HTML 
    网页的具体内容和结构

    CSS 
    网页的样式(美化网页最重要的一块)

    JavaScript 
    网页的交互效果,比如对用户鼠标事件作出响应

    HTML

    什么是HTML

    HTML的全称是HyperTextMarkupLanguage,超文本标记语言 
    其实它就是文本,由浏览器负责将它解析成具体的网页内容

    比如,浏览器会将下面的HTML代码

    <ul>
        <li>知乎</li>
        <li>CSDN</li>
        <li>博客园</li>
    </ul>
     
    • 1
    • 2
    • 3
    • 4
    • 5

    转化为 
    知乎 
    黑马 
    CSDN 
    的网页内容

    HTML的组成

    跟XML类似,HTML由N个标签(节点、元素、标记)组成

    HTML语法非常松散

    常见的HTML标签

    • 标题:h1,h2,h3,h4,h5…
    • 段落:p
    • 换行:br
    • 容器:div,span(用来容纳其他标签)
    • 表格:table,tr,td
    • 列表:ul,ol,li
    • 图片:img
    • 表单:input
    • 链接:a 
      推荐开发工具(网络三剑客)dreamweawer、flash、fireworks;WebStorm.
    <html>
        <!-- 网页的标题、图标... -->
        <head>
            <mate charset="utf-8">
            <title>第一个网页</title>
        </head>
        <!-- 网页的具体内容 -->
        <body>
            这是网页的内容
            <a href="http://www.baidu.com" target="_blank">百度</a>
    
            <h1>666666666</h1>
            <h2>666666666</h2>
            <h3>666666666</h3>
            <h4>666666666</h4>
            <h5>666666666</h5>
    
            <p>ppppppppppp</p>
    
        <div>
            <p>ppppppppppp</p>
        </div>
    
            <ul>
                <li>hahaha</li>
                <li>hahaha</li>
                <li>hahaha</li>
            </ul>
    
            <ol>
                <li>ahahah</li>
                <li>ahahah</li>
                <li>ahahah</li>
            </ol>
    
        <img src="text.png">
        </body>
    </html>
     
    • 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

    CSS

    什么是CSS

    CSS的全称是Cascading Style Sheets,层叠样式表 
    它用来控制HTML标签的样式,在美化网页中起到非常重要的作用

    CSS的编写格式是键值对形式的,比如

    color : red 
    background-color : blue 
    font-size : 20px 
    冒号左边的是属性名,冒号右边的是属性值

    CSS三种书写方式

    • 行内样式:(内联样式)直接在标签的style属性中书写
    <span style="color:red;background-color:red;">123</span>
     
    • 1
    • 内页样式:在本网页的style标签中书写
    <span>123</span>
    <style type="text/css">
        span {
            color:yellow;
            background-color:blue
        }
    </style>
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    外部样式:在单独的CSS文件中书写,然后在网页中用link标签引用 
    test.css

    span {
            color:yellow;
            background-color:blue
        }
     
    • 1
    • 2
    • 3
    • 4

    test.html

    <span>123</span>
    <link rel="stylesheet" herf="test.css">
     
    • 1
    • 2

    CSS选择器

    选择器的作用

    选择对应的标签,为之添加样式

    标签选择器 根据标签名找到标签

    类选择器 标签可以有多个类

    id选择器 id是唯一的,不能一样

    选择器组合 中间不留空格,粘在一起

    后代选择器 中间一个空格,不管嵌套多少层

    相邻兄弟选择器

    属性选择器

    <html>
    <head lang="en">
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            /*标签选择器*/
            p{
                color:red;
            }
            /*类选择器*/
            .first{
                color:red;
            }
            .second{
                color:blue;
            }
            /*id选择器*/
            #first{
                color:yollew;
            }
            #second{
                color:green;
            }
            /*群组选择器*/
            .first, #second, h1{
            }
            /*选择器组合*/
            div.first{
            }
            /*后代选择器*/
            div p{
            }
            /*子标签选择器*/
            div > p{
            }
            /*相邻兄弟选择器*/
            divp{
            }
            /*属性选择器*/
            div[name]{
            }
            div[name][age]{
            }
            div[name="jack"]{
            }
        </style>
    
    </head>
    <body>
        <div>
            <p>p1</p>
            <span>
                <p>p2</p>
            </span>
        </div>
        <div name="jack">div1</div>
        <div age="10">div2</div>
        <p>与div相邻的p</p>
    
        <div class="first">123</div>
        <div id="first">123</div>
    
        <p class="first second">123</p>
        <p id="second">123</p>
    
        <h1>hhh</h1>
    </body>
    </html>
     
    • 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

    伪类

    属性 描述
    :active 向被激活的元素添加样式
    :focus 向拥有键盘输入焦点的元素添加样式
    :hover 当鼠标悬浮在元素上方时,向元素添加样式
    :link 向未被访问的链接添加样式
    :visited 向已被访问的链接添加样式
    :first-child 向元素的第一个子元素添加样式
    :lang 向带有指定lang属性的元素添加样式
    :first-letter 向文本的第一个字母添加特殊样式
    :first-line 向文本的首行添加特殊样式
    :before 在元素之前添加内容
    after 在元素之后添加内容
    <html>
    <head lang="en">
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            div {
                width:100px;
                height:100px;
                background-color:red;
            }
            div:hover{
                background-color:blue;
            }
            div:before{
                content:"666";
            }
        </style>
    
    </head>
    <body>
        <div>
    
        </div>
    </body>
    </html>
     
    • 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

    选择器优先级

    针对性越强,优先级越高 
    选择器的权值 
    通配选择符(*):0 
    标签:1 
    :10 
    属性:10 
    伪类:10 
    伪元素:1 
    id:100 
    important:1000

    原则:选择器的权值加到一起,大的优先;如果权值相同,后定义的优先 
    important > 内联 > id > 类 > 标签|伪类|属性选择器 > 伪元素 > 通配符 > 继承

    CSS标签的类型

    HTML有N多标签,根据显示的类型,主要可以分为2大类

    块级标签,独占一行的标签 
    行内标签(内联标签),多个行内标签能同时显示在一行

    修改标签的显示类型

    CSS中有个display属性,能修改标签的显示类型

    属性 说明
    none 隐藏标签
    block 块级类型,独占一行,能随时设置宽度和高度
    inline 行内类型(内联类型),多个行内标签可以显示在同一行,宽度和高度取决于内容尺寸
    inline-block 行d内-块级类型(内联-块级类型),多个行内标签可以显示在同一行,能随时设置宽度和高度

    CSS属性

    CSS有N多属性,根据继承性,主要可以分为2大类

    可继承属性 
    - 父标签的属性值会传递给子标签 
    - 一般是文字控制属性

    不可继承属性 
    - 父标签的属性值不能传递给子标签 
    - 一般是区块控制属性

    CSS属性-可继承属性

    所有标签可继承 
    visibility、cursor

    内联标签可继承 
    letter-spacing、word-spacing、shite-space、line-height、color、font、font-family、font-size、font-style、font-variant、font-weight、text-decoration、text-transform、direction

    块级标签可继承 
    text-indent、text-align

    列表标签 
    list-style、list-style-type、list-style-position、list-style-image

    CSS属性-不可继承属性

    display、margin、border、padding、background 
    height、min-height、max-height、width、min-width、max-width 
    over-flow、position、left、right、top、bottom、z-index 
    float、clear 
    table-layout、vertical-align 
    page-break-after、page-bread-before 
    unicode-bidi

    盒子模型

    网页上每一个标签都是一个盒子 
    每个盒子都有四个属性

    属性 说明
    内容(content) 盒子里装的东西,网页中通常是指文字和图片
    填充(padding,内边距) 怕盒子里装的(贵重的)东西损坏,而添加的泡沫或者其它抗震的辅料
    边框(border) 盒子本身
    边界(margin,外边距) 盒子摆放的时候不能全部堆在一起,盒子之间要留一定空隙保持通风,同时也为了方便取出
    <html>
    <head lang="en">
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            div {
                width: 100px;
                height: 100px;
                background-color: blue;
                margin-top: 20px;
                padding-top: 20px;
                border: 20px solid red;
                border: 5px dashed red;/*虚线*/
                        }
        </style>
    
    </head>
    <body>
        <div>123</div>
        <div>456</div>
    </body>
    </html>
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    内容(content)属性

    属性 描述
    height 设置元素高度
    max-height 设置元素的最大高度
    max-width 设置元素的最大宽度
    min-height 设置元素的最小高度
    min-width 设置元素的最小宽度
    width 设置元素的宽度

    填充(padding,内边距)属性

    属性 描述
    padding 在一个声明中设置所有内边距属性
    padding-bottom 设置元素的下内边距
    padding-left 设置元素的做内边距
    padding-right 设置元素的有内边距
    padding-top 设置元素的上内边距

    边框border属性

    属性 描述
    border-width 宽度
    border-style 样式
    border-color 颜色
    border-radius 圆角

    边界margin属性

    属性 描述
    margin 在一个声明中设置所有外边距属性
    margin-bottom 设置元素的下外边距
    margin-left 设置元素的左外边距
    margin-right 设置元素的右外边距
    margin-top 设置元素的上外边距
    展开全文
  • 互联网+时代,拥有个人网站是在正常不过的了,那么创建一个个人网站到底需要多少钱呢? 一、域名价格(以西部数码为例) .net后缀域名原价:70元68元/首年;.top后缀域名原价:26元4元/首年;.cLub后缀域名原价:30...
  • Java面试题大全(2020版)

    万次阅读 多人点赞 2019-11-26 11:59:06
    发现网上很多Java面试题都没有答案,所以花了...、Java 基础 1. JDK 和 JRE 什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 JRE:Java Runtime Environ...
  • 电脑上访问一个网页的整个过程

    千次阅读 2017-10-07 15:18:43
    电脑上访问一个网页,整个过程是怎么样的(url:www.sina.com):其中DNS、HTTP、TCP、OSPF、IP、ARP具体实现。1.若DNS缓存中没有相关数据,则IE浏览器先向DNS服务器发出DNS请求:2.这一过程的目的是获取...
  • 如何判断一个网页是否更新

    千次阅读 2016-12-03 20:19:28
    在爬虫网页时,我们会向服务器发送head请求,而在返回的head头中,我们可以得到Last-Modifed, 即网页最后的修改时间。但是这判断主要在于静态页面,在动态页面中Last-Modifed只是服务器最后发送Res 2.基于局部...
  • 入门学习Linux常用必会60命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    hda1中的“1”代表hda的第一个硬盘分区 (partition),hda2代表hda的第二主分区,第一个逻辑分区从hda5开始,依此类推。此外,可以直接检查 /var/log/messages文件,在该文件中可以找到计算机开机后系统已辨认出来的...
  • 经常遇到甲方一上来咨询第一句就问:做一个外贸网站需要多少钱? 无论哪个建站公司,都会出现相似的这么一个场景,在还没有清楚对方明确需求的时候,一旦提供报价之后,甲方如果说报价有些高了,后面不管如何与甲方...
  • 在互联网历史中,网页设计师和网页开发人员这两不同的行业分工一直都扮演着不可或缺的角色。谁是主角,谁是配角的争论就如鸡和蛋谁先谁后的争论一样,喋喋不休却没有意义。但是,如果从客观的角度来讲,那么你...
  • 爬虫爬取网站全部网页

    万次阅读 2019-01-01 11:41:08
    # 获取目标网站的大量相关网页链接 if __name__ == '__main__': import ClimbHealthSkyCom ClimbHealthSkyCom.main() # 对链接进行进一步处理,去重 def LinkDeduplication(): print('开始链接去重') try: ...
  • 爬取一个网站

    千次阅读 2019-06-16 20:36:10
    如果一个页面10个链接,网站5个页面深度(中等规模网站的主流深度),如果要采集整个网站,一共需要采集的网页数量就是10^5,即100000个页面,因为很少有网站会涉及到这么多的网页,因为很大一部分是因为网页...
  • 小媛:bit 哥,最近人找我做一个网页,但是我不会做,300块钱呢。 ????1_bit:啥网页?给你300? ????小媛:吃鸡的网页,赚了300我就可以吃半个月了,下面就是一个示例。 ????1_bit:哈哈哈,我觉得一周你就用完了...
  • 网页简介

    千次阅读 2019-06-20 15:14:57
    、HTML起源 二、组成部分 三、
  • 一个网站真的那么难吗?

    万次阅读 2018-05-14 09:26:24
    现在这个互联网时代,...一个叫做水果哥,一个叫做水果妹。地点是一个普通的小乡村,水果哥只会闷头搞技术,水果妹却是精通运营之道。(怎么一看这么像程序猿跟产品|运营的关系%&gt;_&lt;%,其实他们关系很...
  • 网页宽度一般设置多少才合适?

    千次阅读 2018-09-16 13:18:56
    许多的网页设计在进行网页布局设计时,进行界面网页的宽度尺寸设计都比较迷茫,800600尺寸及1024768尺寸的分辨率下,网页应该设计为多少像素才合适呢?太宽就会出现水平滚动条了,下面我们就网页设计的标准尺寸进行讲解....
  • 网站SEO优化

    千次阅读 多人点赞 2018-03-06 16:05:18
    SEO关键词密度优化:关键词密度一般多少合适呢? 我是怎么迅速提高网站百度排名的 长沙SEO霜天详解各域名后缀何不同 SEO优化:浅析网站优化之首页的布局设计及要求 网页设计与架构的SEO优化原则是什么 网站检查要点 ...
  • 我们平时上网浏览的所有页面,就是网页,而一个网站是由网页组成,小到一个网页,大到50个网页,而某些大型的网站可能包含了上千万个网页,打开网站的第一个页面叫做首页。 专有名词:网页,网站,主页...
  • 一个网页通用的测试用例

    千次阅读 2016-05-06 17:50:14
    一个网页通用的测试用例 具体需求: 有一个登陆页面, (假如上面2个textbox, 一个提交按钮。 请针对这个页面设计30个以上的testcase.) 此题的考察目的:面试者是否熟悉各种测试方法,是否丰富的Web测试经验,...
  • 前端面试题

    万次阅读 多人点赞 2019-08-08 11:49:01
    HTML文件里开头都有个很重要的东西,Doctype,知道这是干什么的吗? 21 Quirks模式是什么?它和Standards模式什么区别 21 div+css的布局较table布局什么优点? 22 img的alt与title何异同? strong与em的...
  • 如何用PHP完整的开发一个网站

    万次阅读 2018-12-26 09:53:38
    了解Cookie或者Session种机制 了解种模板操作机制和使用 手头收藏一些好的常用类或方法,能提高我们的开发的速度。如:分页、上传、字符过滤、数据库操作、生成HTML、文件操作等。 (2)...
  • 实现一个类,抓取一个网站所有页面 实现思路:一边添加url,一边抓取,一直进行下去就可以了,直到列表遍历完成,说明没有新的url可供抓取,即抓取完成。 实际上是图的广度优先遍历。 import urllib.request ...
  • 前端面试锦集

    千次阅读 多人点赞 2019-07-20 13:41:45
    一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程...
  • 近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k下的都会出笔试题 ...同时分享一个自己录制的CSS3动画特效经典案例【推荐教程】--后期会更新vue框架 微信小程序等内容。 https://ke.qq.com/cou...
  • 一个网页从开始请求到最终显示的完整过程一个网页从请求到最终显示的完整过程一般可分为如下7个步骤: 1. 在浏览器中输入网址; 2. 发送至DNS服务器并获得域名对应的WEB服务器的IP地址; 3. 与WEB服务器建立TCP...
  • 如何区分静态网页与动态网页

    千次阅读 2018-12-29 11:52:38
    ”对搜索引擎检索存在一定的问题,搜索引擎通常不行能从一个网站的数据库中访问全部页面,或者出于技能方面的考虑,搜索蜘蛛不去抓取网址中“?”后面的内容,因此选用动态页面的网站在进行搜索引擎推广时需求做一定...
  • 怎么区分静态网页和动态网页

    千次阅读 2019-09-25 03:38:36
    静态网页网站建设的基础,静态网页和动态网页之间也并不矛盾,为了网站适应搜索引擎检索的需要,即使采用动态网站技术,也可以将网页内容转化为静态网页发布。 、静态web页面,一般指html: 1、在静态Web程序中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 98,425
精华内容 39,370
关键字:

一个网站有多少网页