zoukankan      html  css  js  c++  java
  • 爬虫之链式调用、beautifulsoup、IP代理池、验证码破解

    一、链式调用

    在python中实现链式调用只需在函数返回对象自己就行了。

     1 class Person:
     2     def name(self, name):
     3         self.name = name
     4         return self
     5 
     6     def age(self, age):
     7         self.age = age
     8         return self
     9 
    10     def show(self):
    11         print "My name is", self.name, "and I am", self.age, "years old."
    12 
    13 p = Person()
    14 p.name("Li Lei").age(15).show()
    

    二、beautifulsoup

    2.1介绍

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4

    #安装 Beautiful Soup
    pip install beautifulsoup4
    
    #安装解析器
    Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:
    
    $ apt-get install Python-lxml
    
    $ easy_install lxml
    
    $ pip install lxml
    
    另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:
    
    $ apt-get install Python-html5lib
    
    $ easy_install html5lib
    
    $ pip install html5lib
    

    下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.

    解析器 使用方法 优势 劣势
    Python标准库 BeautifulSoup(markup, "html.parser") Python的内置标准库执行速度适中文档容错能力强 Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
    lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快文档容错能力强 需要安装C语言库
    lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"])``BeautifulSoup(markup, "xml") 速度快唯一支持XML的解析器 需要安装C语言库
    html5lib BeautifulSoup(markup, "html5lib") 最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 速度慢不依赖外部扩展

    中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

    2.2 基本使用

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    
    #基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
    res=soup.prettify() #处理好缩进,结构化显示
    print(res)
    

    2.3遍历文档树

    每一个BeautifulSoup 的对象的标签都可以看成一个个对象,标签的属性可以看成对象的属性,通过遍历、查找文档树查找到的标签依然可以看成一个对象。

    #遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
    #1、用法
    #2、获取标签的名称
    #3、获取标签的属性
    #4、获取标签的内容
    
    # 必须掌握的
    head=soup.head
    print(head)
    p=soup.p
    print(p)
    p=soup.body.p
    print(p)
    
    # 获取p标签的名字
    p=soup.body.p
    print(p.name)
    
    # 获取属性
    # 当你获取class的时候,获取的是个列表?class可以有多个
    p=soup.body.p
    print(p['class'])
    print(p['id'])
    print(p.attrs.get('class'))此方法与上面的方法相同
    
    # 获取内容
    # text:获取所有的文字,包括子标签(笔记多),爬去文章时可以直接获取文章内容div的text就能取出文章内的所有文字
    # string:获取当前第一级目录的文字,如果嵌套多层,就取不出文字
    # strings:生成器,每一层的文字都放在里面
    p=soup.body.p
    print(p.text)
    print(p.string)
    print(list(p.strings))
    
    # 用的比较少(了解)
    #5、嵌套选择
    print(soup.head.title.string)
    print(soup.body.a.string)
    
    #6、子节点、子孙节点
    print(soup.body.p.contents)
    print(list(soup.body.p.children))
    print(list(soup.body.p.descendants)) #子子孙孙
    
    #7、父节点、祖先节点
    print(soup.body.p.parent)  #直接父节点
    print(list(soup.body.p.parents)) # 父亲,父亲的父亲。。。全都放到生成器中
    
    #8、兄弟节点
    print(soup.a.next_sibling) #下一个兄弟
    print(soup.a.previous_sibling) #上一个兄弟
    

    2.4 搜索文档树

    Beautiful Soup定义了很多搜索方法,这里着重介绍2个:find()find_all() 。其它方法的参数和用法类似,请读者举一反三。

    find_all( name , attrs , recursive , text , **kwargs )、find( name , attrs , recursive , text , **kwargs )

    find_all找出所有满足条件的标签,如果有多个就放在列表中;find找出满足条件的第一个标签,就算有多个也只找第一个,具体使用方法如下:

    # p是标签对象,跟soup是一样的
    # p=soup.find(name='p',class_='story')
    # print(p)
    # b=soup.find(name='b')
    # print(b)
    
    # 通过属性查找方式一
    # b=soup.find(id='id_b')
    # print(b)
    
    # 通过属性查找的方式二
    # b=soup.find(attrs={'id':'id_b'})
    # p=soup.find(attrs={'class':'story'})
    # print(p)
    
    # 列表查找
    # ret=soup.find_all(name=['p','b'])
    # ret=soup.find_all(id=['id_b','link1'])
    # print(ret)
    
    # 正则
    # import re
    # # 查找名字以b开头的标签
    # # ret=soup.find_all(name=re.compile('^b'))
    # ret=soup.find_all(id=re.compile('^l'))
    # print(ret)
    
    # True
    # 查找所有有id的标签
    # ret=soup.find_all(id=True)
    # ret=soup.find_all(name=True)
    # print(ret)
    
    # 方法
    # def has_class_but_no_id(tag):
    #     return tag.has_attr('class') and not tag.has_attr('id')
    # ret=soup.find_all(has_class_but_no_id)
    # print(ret)
    
    # 取属性,取文字
    # tag对象['src']   tag对象.attrs.get('src')
    # tag对象.text   string
    
    # 遍历文档树和搜索文档树可以同时用
    # soup.body.find(name='p').b
    # soup.body.find(name='p').find()
    # print(type(soup))
    
    # #Tag对象用起来跟BeautifulSoup对象用起来完全一样
    # body=soup.body
    # print(type(body))
    
    # 拓展 链式调用(跟语言没关系,jq)
    # 链式调用在python中如何实现?点多少次,其实还是对象本身
    # class A:
    #     def test(self,name):
    #         self.name=name
    #         return self
    #     def test2(self,age):
    #         self.age=age
    #         return self
    
    # a=A()
    # a.test('lqz').test2(19)
    # print(a.age)
    
    
    # bs4 其他用法
    #limit 限制查找的个数
    # ret=soup.find_all(name='p',limit=1)
    # print(ret)
    # soup.find_all()
    
    # recursive 是否递归查找
    # ret=soup.body.find_all(name='p',recursive=False)
    # ret2=soup.body.find_all(name='p',recursive=True)
    # print(len(ret))
    # print(len(ret2))
    

    2.5修改文档树

    Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树,具体使用方法参见Beautiful Soup 4.2.0 文档

    链接:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id40

    2.6总结

    # 总结:
    #1、推荐使用lxml解析库
    #2、三种选择器:标签选择器,find与find_all,css选择器
        1、标签选择器筛选功能弱,但是速度快
        2、建议使用find,find_all查询匹配单个结果或者多个结果
        3、如果对css选择器非常熟悉建议使用select
    #3、记住常用的获取属性attrs和文本值get_text()的方法
    

    2.7实例:爬取小说三国演义

    import requests,re,os
    from bs4 import BeautifulSoup
    
    ret = requests.get('http://www.shicimingju.com/book/sanguoyanyi.html')
    # print(ret.text)
    soup = BeautifulSoup(ret.text,'lxml')
    mulu_li = soup.find(name='div',class_='book-mulu')
    # print(mulu_li)
    ret1 = soup.select('.book-mulu>ul>li')
    #http://www.shicimingju.com/book/sanguoyanyi/1.html
    content_str = ''
    if not os.path.isdir('三国演义'):
        os.mkdir('三国演义')
    
    #分章节下载
    for i in ret1:
        # print(i.text)
        name = i.text
        url = 'http://www.shicimingju.com' + i.find(name='a')['href']
        # print(url)
        ret2 = requests.get(url)
        soup = BeautifulSoup(ret2.text, 'lxml')
        div = soup.find(name='div', class_="card bookmark-list")
        content = div.text
        head = div.find(name='h1').text
        with open(f'三国演义/{head}.md','wt',encoding='utf-8') as f:
            f.write(content)
            
    #统一下载到一个文件
    # for i in ret1:
    #     # print(i.text)
    #     name = i.text
    #     url = 'http://www.shicimingju.com' + i.find(name='a')['href']
    #     # print(url)
    #     ret2 = requests.get(url)
    #     soup = BeautifulSoup(ret2.text, 'lxml')
    #     div = soup.find(name='div', class_="card bookmark-list")
    #     content_str += div.text
    # with open('三国演义/三国演义.md','wt',encoding='utf-8') as f:
    #       f.write(content_str)
    #       f.flush()
    #       print('下载完成')
    # print(content_str)
        # head = div.find(name='h1').text
        # with open(f'三国演义/{head}.md','wt',encoding='utf-8') as f:
        #     f.write(content)
    
        # print(content)
    

    2.8实例:爬取盗墓笔记

    #爬盗墓笔记
    ret = requests.get('http://www.dmbj.cc/')
    ret.encoding = 'utf-8'
    # print(ret.text)
    soup = BeautifulSoup(ret.text,'lxml')
    li_list = soup.find_all(name='li',class_='pop-book')
    
    for i in li_list:
    
        book_name1 = i.text.strip()
        # print(book_name1)
        book_name = book_name1.strip('
    南派三叔')
        print(book_name)
        book_url = i.find(name='a')['href']
        ret2 = requests.get(book_url)
        ret2.encoding = 'utf-8'
        soup2 = BeautifulSoup(ret2.text, 'lxml')
        # print(ret2)
        content_div = soup2.find(name='div',class_="xsbox clearfix")
        url = content_div.find_all(name='a')
        if not os.path.isdir(f'{book_name}'):
            os.mkdir(f'{book_name}')
        # print(content_div)
    
        for j in url:
            # print(j.text)
            content_url = j['href']
            content_name = j.text
            if content_name[-1] == '?':
                content_name = content_name.strip('?')
            ret3 = requests.get(content_url)
            ret3.encoding = 'utf-8'
            soup3 = BeautifulSoup(ret3.text, 'lxml')
            content = soup3.find(name='div',class_="m-post").text
    
            with open(f'{book_name}/{content_name}.txt', 'wt', encoding='utf-8') as f:
    
                f.write(content)
            # print(content)
    

    三、ip代理池(收费代理、免费代理)

    ip代理池就是一个存放有很多ip的数据库,当我们请求这个数据库接口时可以得到一个由接口随机返回的ip和端口,我们可以使用这些ip作为我们的ip去向某个网站发送请求,这样可以防止服务端因为我们请求次数过多而封我们的ip。

    #代理的使用方法,proxies内是我们的代理ip
    ret=requests.get('http://101.133.225.166:8088/',
                     proxies={'http':'222.95.241.88:3000'}
     )
    

    在访问某些需要校验cookie的服务端时,只有IP代理池还不够,我们需要做一个cookie池,每次向服务器发送请求时的ip和cookie都是随机组合的,这样服务端就会以为这些请求是不同的用户发出的,从而使我们在爬虫的时候不会被封ip。

    3.1收费代理池

    收费代理池一般是第三方做的ip代理网站,如:http://www.goubanjia.com/

    3.2免费代理池

    我们可以从网上爬取一些免费的代理ip自己做代理池,步骤:自己搭建:flask框架搭建服务,后台用爬虫(requests爬取免费),放入redis。

    当然,我们还可以使用GitHub上开源的个人代理池项目,这时别人写好的项目,我们只需要部署到自己的服务器上就可以使用。自己爬的代理ip需要我们定时对这些ip进行测试,保证ip是可用的,测试方式:用这些ip向某个网站发送请求,如果有响应就可以使用。

    #1  下载下来,打开
    #2 安装依赖  pip3 install -r requirements.txt
    #3 修改配置文件Config/setting.py
    35行左右,意思是爬取的代理放到redis中,
    DB_TYPE = getenv('db_type', 'redis').upper()
    DB_HOST = getenv('db_host', '127.0.0.1')
    DB_PORT = getenv('db_port', 6379)
    DB_PASSWORD = getenv('db_password', '')
    #4  跑项目 可以在cli目录下通过ProxyPool.py启
    python3 proxyPool.py schedule:爬取代理
    python3 proxyPool.py webserver:启动服务
    #5 测试
    http://127.0.0.1:5010/get/ 发一次,取一个代理ip
    

    四、验证码破解(打码平台)

    这里需要用到第三方的打码平台,从网上的验证码图片,传给它,他就给你识别,(12306的验证码,模拟登陆12306)。

    我们还可以使用一些程序去识别一些图片,但是一般识别率比较低。

    4.1用python如何调用dll文件

    python调用dll详解参考链接https://www.cnblogs.com/blog-rui/p/11662827.html

  • 相关阅读:
    window linux pycharm 相互协作
    再次校验环境
    转 安装 ubuntu后 软件处理 -感谢博主skykingf csdn
    NSError是向用户传递详细错误信息的不错的选择
    Node.js学习笔记-入门
    UIKit和CSS布局方式的差异
    继承缺陷以及替代方案
    HTML、HTML DOM、Javascript、CSS以及jQuery使用小结
    关于cookies
    一个诡异bug---symbol not found: objc_setProperty_atomic
  • 原文地址:https://www.cnblogs.com/ghylpb/p/12388646.html
Copyright © 2011-2022 走看看