美文网首页
爬虫小结

爬虫小结

作者: 岸与海 | 来源:发表于2018-12-23 14:36 被阅读0次

    爬虫:网络爬虫机器人,从互联网自动抓取数据的程序

    理论上:通过浏览器看到的数据,我们一般都是可以获取到的

    爬虫的作用:

    1. 搜索引擎
      2.商品比价(慧慧购物助手)
      3.知乎的数据分析平台(知乎专栏,数据冰山)

    网页的三大特征:

    1. 每一个网页都有一个唯一的url(统一资源定位符),来进行定位
    2. 网页都是通过HTMl(超文本)文本展示的
    3. 所有的网页都是通过http<超文本传输协议>(HTTPS)协议来传输的

    爬虫的流程

    1. 分析网站,得到目标url
    2. 根据url,发起请求,获取页面的HTML的源码
    3. 从页面源码中提取数据
      a. 提取到目标欧数据,做数据的赛选和持久化存储
      b. 从页面中提取到新的url地址,继续执行第二部操作
    4. 爬虫结束:所有的目标url都提取完毕,并且得到了数据,再也没有其他请求任务了,这是意味着爬虫结束

    通用爬虫抓取网页的流程:

    1. 选取一部分的url作为种子url,将这些url放入到带爬取得任务队列里
    2. 从带爬取得任务队列中取出url,发起请求,将获取到的页面源码存储到本地,并将已经爬取过的url,放入已爬取队列中
    3. 从已爬取url的响应结果中,分析提取其他的url地址,继续添加到带爬取队列中,之后就是不断的循环,查到所有的url都提取完毕

    通用爬虫的缺点:

    1)必须遵守roobot协议:就是一个规范,告诉搜索引擎,哪些目录下的资源允许爬虫,哪些目录下的资源不允许爬取
    ‘User-agent’:该项值用来表示是哪家的搜索引擎
    ‘allow’:允许被爬取的url
    ‘disallow’:不允许被爬取的url
    2)搜索引擎返回的都是网页,并且返回90%的都是无用的数据
    3)不能够跟剧不同的用户需求或者检索结果返回不同的结果
    4)通过爬虫对于对媒体的文件不能够获取

    OSI七层协议

    从上往下:
    应用层:为用户的应用程序提供网络服务的(http,https,ftp。。。。。)
    表示层:负责端到端的数据信息可以被另一个主机所理解和识别,并且按照一定的格式将信息传递到会话层
    会话层:管理主机之间的会话进程,负责建立,管理,和终止会话进程
    传输层:进行数据传输(TCP UDP)
    网络层: 路由器
    数据链路层:网桥 交换机
    物理层 : 网线 网卡 集线器 中继器

    常见的请求状态码

    200 :请求成功

    301 : 永久重定向
    302 : 临时重定向

    401 : 未授权
    403 : 服务器拒绝访问
    404 : 页面丢失
    405 : 请求方式不对
    408 : 请求超时

    500 : 服务器错误
    503 : 服务器不可用

    发起请求:

    会携带请求头:
    ’USer-Agent‘:模拟浏览器请求
    ‘Cookies’:存储在浏览器里,使用cookie表明身份
    ‘Refere’:说明当前请求是从哪个页面发起

    使用urllib发起请求

    #目标url
    url = 'http://www.baidu.com/'
    
    # request.urlopen():使用urlopen方法模拟浏览器发起请求
    """
    url, 请求的目标url地址
    data=None,默认情况为None,表示发起的是一个get请求,不为None,则发起的是一个post请求
    timeout=,设置请求的超时时间 
    cafile=None, 设置证书
    capath=None, 设置证书路径
    cadefault=False, 是否要使用默认证书(默认为False)
    context=None:是一个ssl值,表示忽略ssl认证
    """
    
    #是一个ssl值,表示忽略ssl认证(如果请求出现了ssl证书认证错误,
    # 我们就需要设置ssl._create_unverified_context(),忽略证书认证)
    content = ssl._create_unverified_context()
    response = request.urlopen(url,timeout=10,content=content)
    #从response响应结果中获取参数
    #状态码
    code = response.status
    print(code)
    #获取页面源码的二进制数据
    b_html = response.read()
    print(type(b_html),len(b_html))
    #获取响应的响应头部(Response Headers)
    res_headers = response.getheaders()
    print(res_headers)
    #获取响应头中指定参数的值
    cookie_data = response.getheader('Set-Cookie')
    print(cookie_data)
    #reason返回一个响应结果的原因
    reason = response.reason
    print(reason)
    
    #将获取到的二进制数据,转换为字符串decode
    str_html = b_html.decode('utf-8')
    print(type(str_html))
    
    with open('b_baidu.page.html','w') as file:
        # file.write(b_html)
        file.write(str_html)
    
    
    #如果请求要携带请求头
    
    #需要先构建一个request对象
    """
    url:发起请求的url地址
    data=None, 默认情况为None,表示发起的是一个get请求,不为None,则发起的是一个post请求
    headers={},设置请求头(headers对应的数据类型是一个字典)
    origin_req_host=None, (指定发起请求的域)
    unverifiable=False,忽略SSL认证
    method=None:指定发起请求的方式
    """
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    req = request.Request(url,headers=req_header)
    
    #根据构建的req请求对象发起请求
    response = request.urlopen(req)
    response.status
    

    正则

    . :表示匹配除了换行符之外的任意字符
    \ :转义字符
    [a-z] : 匹配a-z里面的任意一个字符
    
    \d: 匹配数字 -> [0-9]
    \D: 匹配非数字 [^\d]
    \s: 匹配空白字符(空格,\n,\t...)
    \S: 匹配非空白字符 
    \w: 匹配单词字符 [A-Za-z0-9_]
    \W: 匹配非单子字符
    
    ^:匹配以...开头
    $:匹配以....结尾
    
    ():分组
    |:或
    
    多字符匹配
    *:匹配*前面的字符任意次数
    + : 匹配+号前面的字符至少1次
    ?: 匹配?前面的字符0次或1次
    {m}:匹配{m}前面的字符m次
    {m,n}:匹配{m,n}前面的字符m~n次
    
    非贪婪匹配
    *?
    +?
    ??
    {m,n}?
    
    

    列子

    import re
    
    #把正则表达式构建为一个pattern对象
    sub_str = 'abcdefabcd'
    pattern = re.compile('b')
    #从字符串的起始位置开始匹配,开头就必须符合正则规则,
    # 如果匹配到结果了返回结果,如果匹配不到返回None,单次匹配
    result = re.match(pattern,sub_str)
    print(type(result))
    if result:
        print(result.group())
    
    #在整个字符串中进行匹配,同样是单次匹配,匹配到结果立即返回
    #匹配不到则返回None
    result = re.search(pattern,sub_str)
    print(result.group())
    
    # 再整个字符串中进行匹配,匹配出所有符合正则规则的结果,
    # 以列表的形式返回
    result = re.findall(pattern,sub_str)
    print(result)
    
    #再整个字符串中进行匹配,匹配出所有符合正则规则的结果,
    #但是返回的是一个迭代器
    result = re.finditer(pattern,sub_str)
    # <class 'callable_iterator'>
    print(type(result))
    for note in result:
        #<class '_sre.SRE_Match'>
        print(type(note))
        print(note.group())
    #替换re.sub()
    url = 'http://www.baidu.com/s?kw=aaa&pn=20'
    # pattern, \正则规则
    # repl, \要替换的字符串
    # string,原始字符串
    pattern = re.compile('pn=\d+')
    result = re.sub(pattern,'pn=30',url)
    print(result)
    
    #分割re.split()
    pattern = re.compile('[=:&]')
    #pattern, string
    result = re.split(pattern,url)
    print(result)
    
    sub_html = """
    <div class="threadlist_title pull_left j_th_tit ">
        
        
        <a rel="noreferrer" href="/p/5982749825" title="来聊" target="_blank" class="j_th_tit ">来聊</a>
    </div>
    """
    #re.S让点可以匹配包括换行符的任意字符
    pattern = re.compile(
        '<div.*?class="threadlist_title pull_left j_th_tit ">'+
        '.*?<a.*?href="(.*?)".*?</div>',re.S
    )
    
    result = re.findall(pattern,sub_html)
    print(result)
    

    cookies的使用

    from urllib import request
    # 目标url:
    # https://www.douban.com/people/175417123/
    
    url = 'https://www.douban.com/people/175417123/'
    
    # 设置请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
        'Cookie': 'bid=a5HEJxBlOLY; douban-fav-remind=1; ll="108288"; _vwo_uuid_v2=D4EC41D965B5FF84E814BF48AE34386A5|f6047e628a6acc98722e3100dfbc399c; __yadk_uid=KpfeK1cgib5IWMKWvG66MnJMbonYvDZa; _ga=GA1.2.36315712.1531837787; douban-profile-remind=1; push_doumail_num=0; push_noty_num=0; __utmv=30149280.17541; _gid=GA1.2.2070226630.1545227516; ps=y; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1545292749%2C%22https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DqpgHwc2FYGfOrGzt4yK3ZwwbraVm_oED80whnivpFaC3kA5IvGnUfQ9FSRZBOEVh%26wd%3D%26eqid%3D85ed620e000397aa000000065c1b4bc8%22%5D; _pk_ses.100001.8cb4=*; __utma=30149280.36315712.1531837787.1545227511.1545292752.48; __utmc=30149280; __utmz=30149280.1545292752.48.37.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmt=1; dbcl2="175417123:yY3DyEelGJE"; ck=FxtM; ap_v=0,6.0; _pk_id.100001.8cb4=7521abce5497fc2c.1531837784.39.1545292778.1545228853.; __utmb=30149280.7.10.1545292752',
    }
    
    req = request.Request(url=url,headers=req_header)
    
    response = request.urlopen(req)
    
    if response.status == 200:
        with open('douban.html','w') as file:
            file.write(response.read().decode('utf-8'))
    

    cookiejar的使用

    #使用cookiejar的目的:管理cookie,保存cookie值,
    #一旦存储cookie之后,下一次发起请求的时候就会携带cookie
    #cookie是保存在内存里面的,最后会进行垃圾回收
    
    from urllib import request,parse
    from http.cookiejar import CookieJar
    
    #创建cookiejar对象,目的如上
    cookie_jar = CookieJar()
    
    #HTTPCookieProcessor创建handle处理器,管理cookiejar
    handler = request.HTTPCookieProcessor(cookie_jar)
    
    #自定义opener
    opener = request.build_opener(handler)
    
    #分析发现
    # https://www.douban.com/accounts/login
    # 没有验证码的情况
    # source: index_nav
    # form_email: 18518753265
    # form_password: ljh12345678
    
    #有验证码的情况
    # source: index_nav
    # form_email: 18518753265
    # form_password: ljh12345678
    # captcha-solution: blade
    # captcha-id: 5IBtw5wm2riyrIrnV3utwUPt:en
    
    url = 'https://www.douban.com/accounts/login'
    
    form_data = {
        'source': 'index_nav',
        'form_email': '18518753265',
        'form_password': 'ljh12345678',
        'captcha-solution': 'noise',
        'captcha-id': 'waNQIJD6TkMaF4M51PFg5kYh:en'
    }
    
    form_data = parse.urlencode(form_data).encode('utf-8')
    
    #设置请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    
    #够建一个request对象
    req = request.Request(url,headers=req_header,data=form_data)
    
    #发起请求
    response = opener.open(req)
    
    #登录成功后访问个人主页,能够成功获取到个人主页信息,说明确实保存了cookie
    #并且在一下次发起请求的时候携带了cookie
    url = 'https://www.douban.com/people/175417123/'
    
    req = request.Request(url,headers=req_header)
    
    response = opener.open(req)
    
    if response.status == 200:
        with open('douban.html','w') as file:
            file.write(response.read().decode('utf-8'))
    

    urllib.error的使用

    # urllib.error:在发起请求的过程中,可能会因为各种情况
    # 导致请求出现异常,因而导致代码崩溃,所以我们悬疑处理这些异常的请求
    
    from urllib import error,request
    
    # error.URLError
    
    def check_urlerror():
        """
        1.没有网络
        2.服务器连接失败
        3.找不到指定服务器
        :return:
        """
        url = 'http://www.baidu.com/'
        try:
            response = request.urlopen(url,timeout=0.01)
            print(response.status)
        except error.URLError as err:
            #[Errno -2] Name or service not known(未知服务器)
            #timed out:请求超时
            #[Errno -3] Temporary failure in name resolution(没网)
            print(err.reason)
    
    # check_urlerror()
    
    # error.HTTPError是URLError的子类
    
    def check_httperror():
        url = 'https://www.qidian.com/all/nsacnscn.htm'
        try:
            response = request.urlopen(url)
            print(response.status)
        except error.HTTPError as err:
            #HTTPError的三个属性
            #状态码
            print(err.code)
            #返回错误的原因
            print(err.reason)
            #返回响应头
            print(err.headers)
        except error.URLError as err:
            print(err.reason)
    
    check_httperror()
    

    urllib的parse模块的使用

    #urllib的parse模块主要是实现url的解析,合并,编码,解码
    
    from urllib import  parse
    
    #parse.urlparse实现了url的识别和分段
    url = 'https://www.1712B.com/daxuesheng?name=zhangsan#123'
    """
    url,:要解析和才分的url
    scheme='':设置协议,只有在url没有协议的情况下才会生效
    allow_fragments=True:是否忽略锚点,默认为True表示不忽略
    """
    result = parse.urlparse(url)
    """
    (scheme='https'(协议), netloc='www.1712B.com'(域), 
    path='/daxuesheng'(路径), params=''(可选参数), 
    query='name=zhangsan'(查询参数), fragment='123'(锚点))
    """
    print(result)
    #取出才分后的某一个参数
    print(result.scheme)
    
    #parse.urlunparse可以实现url的组合
    data = [sub_str for sub_str in result]
    print('-----',data)
    full_url = parse.urlunparse(data)
    print(full_url)
    
    #parse.uurlrljoin需要传递一个基类url,根据基类将某一个不完整的url拼接完整
    sub_url = '/p/123456'
    base_url = 'https://www.1712B.com/daxuesheng?name=zhangsan#123'
    full_url = parse.urljoin(base_url,sub_url)
    print('urljoin',full_url)
    
    #parse.urlencode将字典类型的参数,序列化为url的编码格式的字符串
    parmars = {
        'name':'张三',
        'class':'1712B',
    }
    result = parse.urlencode(parmars)
    print('urlencode',result)
    
    #parse.parse_qs反序列化,将url编码格式的字符串,转为字典类型
    result = parse.parse_qs(result)
    print('parse_qs',result)
    
    #parse.quote可以将中文字符,转为url编码格式
    kw = '摸摸摸'
    result = parse.quote(kw)
    print('quote',result)
    
    #将url编码进行解码
    result = parse.unquote(result)
    print('unquote',result)
    
    
    # 最最常用的urljoin,urlencode两个方法
    

    urllib_proxy的使用

    # urllib下使用代理
    # http/https代理
    # 一定是一个高匿代理理
    # 隐藏真实ip
    
    from urllib import request
    
    #自定义ProxyHandler的目的是为了设置代理,使用代理发起请求
    #proxies:对应的是一个字典
    # 代理有免费代理(西刺,快代理.....)
    # 和收费代理 (西刺,快代理.....,阿布云....)
    # proxies = {
    #     'http':'118.187.58.34:53281',
    #     'https':'124.235.180.121:80',
    # }
    
    #独享代理,需要账号密码做验证的
    proxies = {
        'http':'http://2295808193:6can7hyh@106.12.23.200:16818',
        'https':'https://2295808193:6can7hyh@106.12.23.200:16818'
    }
    handler = request.ProxyHandler(proxies=proxies)
    
    #自定义opener
    opener = request.build_opener(handler)
    
    #url地址
    #https://httpbin.org/get
    url = 'http://httpbin.org/get'
    
    response = opener.open(url)
    
    print(response.status)
    print(response.read().decode('utf-8'))
    

    requests模块

    #pip3 install requests
    #requests模块:是对urllib的封装,可以实现urllib的所有功能
    #并且api调用更加简单方便
    
    import requests
    
    # url = 'http://www.baidu.com/'
    url = 'http://www.sina.com'
    # url, :要请求的目标url
    # params:get请求后面要拼接的参数
    """
    :param method: 要发起的是什么类型的请求.
    :param url: 要请求的目标url
    :param params: get请求后面要拼接的参数
    :param data: Dictionary, post请求的表单数据
    :param json: 传递json数据跟上面的data效果类似
    :param headers: (optional) Dictionary 请求头
    :param cookies: (optional) Dict or CookieJar object (设置cookies信息模拟用户请求)
    :param files: 上传文件
    :param auth: 网站需要验证的信息(账号和密码)
    :param timeout: 设置请求的超时时间
    :param allow_redirects: bool,是否允许重定向
    :param proxies: (optional) Dictionary (设置代理)
    :param verify:  Defaults to ``True``.(忽略证书认证,默认为True表示不忽略)
    """
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    parmars = {
        'wd':'豆瓣'
    }
    # response = requests.get(url,params=parmars,headers=req_header)
    response = requests.get(url,headers=req_header)
    response.encoding='utf-8'
    
    #从响应结果中获取的信息
    #(这里得到的是解码后的字符串)
    html = response.text
    
    """
    #如果使用response.text出现了乱码
    方式一
    #response.content.decode('')
    方式二
    response.encoding=''设置编码类型
    """
    
    #获取bytes类型的数据
    b_html = response.content
    #获取状态码
    code = response.status_code
    #获取响应头
    response_headers = response.headers
    #请求头
    req_headers = response.request.headers
    #获取当前请求的url地址
    current_url = response.url
    #response.json():可以将json字符串转为python数据类型
    print(code)
    print(html)
    
    

    resquests_post请求

    import requests
    
    #url, 目标url
    # data=None,:post请求要上传的表单数据
    
    url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
    
    form_data = {
        'first': 'true',
        'pn': 1,
        'kd': 'python',
    }
    
    #设置请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
        'Referer': 'https://www.lagou.com/jobs/list_python?city=%E5%85%A8%E5%9B%BD&cl=false&fromSearch=true&labelWords=&suginput=',
    }
    
    response = requests.post(url,data=form_data,headers=req_header)
    
    print(response.status_code)
    
    print(response.text)
    
    #可以吧将返回的json字符串转为python数据类型
    data = response.json()
    print(type(data))
    

    requests_outh

    #web客户端验证
    import requests
    
    #设置认证信息
    auth = ('username','password')
    
    url = 'http://192.168.1.110'
    
    response = requests.get(url,auth=auth)
    
    print(response.status_code)
    

    requests下使用cookies

    import requests
    #分析发现
    # https://www.douban.com/accounts/login
    # 没有验证码的情况
    # source: index_nav
    # form_email: 18518753265
    # form_password: ljh12345678
    
    #有验证码的情况
    # source: index_nav
    # form_email: 18518753265
    # form_password: ljh12345678
    # captcha-solution: blade
    # captcha-id: 5IBtw5wm2riyrIrnV3utwUPt:en
    
    url = 'https://www.douban.com/accounts/login'
    
    form_data = {
        'source': 'index_nav',
        'form_email': '18518753265',
        'form_password': 'ljh12345678',
        'captcha-solution': 'violent',
        'captcha-id': 'AuKNJ1FIktyrmpljJ6WAzXo3:en'
    }
    
    #设置请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    
    #发起请求
    response = requests.post(url,headers=req_header,data=form_data)
    
    #使用response.cookies获取cookies信息
    print('模拟登录后的cookies信息',response.cookies)
    print(type(response.cookies))
    print(response.headers)
    
    with open('douban.html','w') as file:
        file.write(response.text)
    
    #requests.utils.cookiejar_from_dict():将字典转为cookiejar
    #requests.utils.dict_from_cookiejar():将cookiejar转为字典
    cookies_dict = requests.utils.dict_from_cookiejar(response.cookies)
    print(cookies_dict)
    #登录成功后访问个人主页,能够成功获取到个人主页信息,说明确实保存了cookie
    #并且在一下次发起请求的时候携带了cookie
    url = 'https://www.douban.com/people/175417123/'
    #设置cookies参数,模拟用户发起请求
    response = requests.get(url,headers=req_header,cookies=cookies_dict)
    
    if response.status_code == 200:
    
        with open('douban1.html','w') as file:
    
            file.write(response.text)
    

    使用requests模块设置代理

    import requests
    
    proxies = {
        'http':'219.238.186.188:8118',
        'https':'222.76.204.110:808',
        'https':'https://username:password@ip:port',
        'http':'http://username:password@ip:port'
    }
    
    url = 'https://httpbin.org/get'
    
    response = requests.get(url,proxies=proxies,timeout=10)
    
    print(response.text)
    
    

    requests.session的使用

    #requests.session():维持会话,可以让我们在跨请求时保存某些参数
    
    
    import requests
    
    #实例化session
    session = requests.session()
    
    #目标url
    url = 'https://www.douban.com/accounts/login'
    
    form_data = {
        'source': 'index_nav',
        'form_email': '18518753265',
        'form_password': 'ljh12345678',
        'captcha-solution': 'stamp',
        'captcha-id': 'b3dssX515MsmNaklBX8uh5Ab:en'
    }
    
    #设置请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    
    #使用session发起请求
    response = session.post(url,headers=req_header,data=form_data)
    
    if response.status_code == 200:
    
        #访问个人主页:
        url = 'https://www.douban.com/people/175417123/'
    
        response = session.get(url,headers = req_header)
    
        if response.status_code == 200:
    
            with open('douban3.html','w') as file:
    
                file.write(response.text)
    

    xpath的使用

    • xpath:可以在xml中查找信息,对xml文档中元素进行遍历和属性的提取

    • xml:被设计的目的是为了传输数据,结构和html非常相识,是一种标记语言

    xpath常见的语法:

    nodename 选取此节点的所有子节点
    /        从根节点开始查找
    //       匹配节点,不考虑节点的位置
    .        选取当前节点
    ..       选取当前节点的父节点
    a/@href        取标签的数据
    a/text()       取标签的文本
    a[@class="123"] 根据class属性寻找标签
    a[@id="123"]    根据id属性寻找标签
    
    a[@id="123"][last()]  取最后一个id为123的a标签
    a[@id="123"][postion() < 2]  取id为123的前两个a标签
    

    相关文章

      网友评论

          本文标题:爬虫小结

          本文链接:https://www.haomeiwen.com/subject/qguikqtx.html