20200225 爬虫-bs4使用及简单代理破解验证码

昨日回顾

## 1 什么是爬虫?

## 2 爬虫的流程

发送http请求----》别人服务器响应----》拿到响应自己解析(re、bs4、lxml)------》入库(mongodb)

分布式爬虫---redis(blpop/brpop:列表,阻塞队列)

集群和分布式:单实例的项目

集群化的部署:一个项目部署在多台机器上

分布式(微服务):一个项目拆成多个部分,放到不同的服务器上,每个项目单独开发,单独上线

## 3 requests模块

模拟发送http请求

​```python
# 1 可以发送任意请求get,post,delete。。。
requests.get()
requests.post()
# 2 携带头信息
#user-agent   referer cookie(cookie池)
requests.get(headers={})
# 3 cookie单独拿出来
requests.get(cookies={})
# 4 get请求携带参数两种方式

# 5 post请求请求体 data/json

# 6 响应对象response 有好多属性

# 7 发送请求,使用代理,随机取一个代理,在列表中通过random

# 8 ssl,timeout,上传文件(项目)

1.链式调用

​```
在方法中实现 返回自己
return  self
即可实现一直...属性
​```

2.bs4的搜索文档树的find有几种方式可以查找标签

​```
五种过滤器

字符串
	soup.find(name='标签名',attrs={'属性':'值'})
列表
	soup.findall(name=['标签名','标签2'])
正则
	使用re.compile('正则规则')
bool
	soup.findall(id=true)
方法
	定义方法
	sopu.find_all(方法)
​```

3.bs4获取标签属性的方式

​```
直接.
标签.name
p['class']
p.attrs.get('class')
​```

4.bs4获取标签内容的三种方式,有什么不同

​```
text	: 获取所有的文本,包括子标签的文字
string	: 获取当前第一级目录的文字
strings	: 获得一个生成器,每层文字放在列表中
​```

5.你验证码如何破解

​```
打码平台申请调用接口
​```


bs4

简介

安装

pip install beautifulsoup4

导入

from bs4 import BeautifulSoup4

参数

# 实例化得到对象
soup = beautifulsoup(ret.text,'lxml')
    '''
    第一个参数 可以是字符串,或者文件对象
    第二个参数 解析的方式(解析库)
    	html.parser		# python自带的
    	lxml	# 需要另外安装解析库 pip install lxml
    '''

使用

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>
"""

# 实例化得到对象
soup = BeautifulSoup(html_doc,'lxml')

# 美化,对标签进行闭合
# soup.prettify()

1 遍历文档树

# 用法: 直接 . 取下一个标签

p = soup.p
print(p)    # 对象 <p class="title"><b>The Dormouse's story</b></p>

基本使用

# 获取标签的名称
print(p.name)   # p



# 获取标签的属性
#     当你获取class的时候,获取的是列表
print(p['class'])   # ['title']
print(p.attrs.get('class'))  # ['title']



# 获取标签的内容
#     text: 获取所有的文字,包括子标签的文字
#     string: 获取当前第一级目录的文字,如果嵌套多层,就取不出文字
#     strings: 获取一个生成器,每层文字分别放在列表中
p = soup.body.p
print(p.text)   # The Dormouse's story
print(p.string)  # The Dormouse's story
print(p.strings) # <generator object _all_strings at 0x00000206A5DE3A98>
print(list(p.strings)) # ["The Dormouse's story"]

用的较少(了解)

# 嵌套选择
p = soup.body.p



# 子节点,子孙节点
    # 子节点
print(soup.body.p.contents)     # [<b>The Dormouse's story</b>]

    # 子孙节点
print(soup.body.p.children)   # <list_iterator object at 0x0000014DDE79CF60>
print(list(soup.body.p.children))   # [<b>The Dormouse's story</b>]

    # 子子孙孙
print(list(soup.body.p.descendants))   # [<b>The Dormouse's story</b>]



# 父节点,祖先节点
print(soup.body.p.parent)   # 直接父节点
print(soup.body.p.parents)   # 所有父集,祖先的节点 生成器



# 兄弟节点
print(soup.a.next_sibling)  # 下一个兄弟
print(soup.a.previous_sibling)  # 上一个兄弟

2.搜索文档树

搜索的查找速度比遍历低

  • find()与find_all()
  • 五种过滤器 : 字符串,列表,正则,bool,方法
# 字符串: 精准匹配

    # 属性查找的方式一
p = soup.find(name='p',class_='story')  # p是标签对象,和soup是一样的
print(p)
    # 属性查找方式二
p = soup.find(name='p',attrs={'class':'story'})
print(p)




# 列表查
ret = soup.find_all(name=['p','a'])
ret = soup.find_all(id=['id_1','link1'])
print(ret)




# 正则  re.compile()
import re
ret = soup.find_all(name=re.compile('^b'))  # 查找名字以b开头的标签




# bool布尔
ret = soup.find_all(id=True)  # 查找所有有ID的标签




# 方法
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')

# 查找有class属性没有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(id='link')



# tag对象与beautifulsoup对象用起来完全一样
soup = BeautifulSoup(html_doc,'lxml')
print(type(soup))
body = soup.body
print(type(body))

3.拓展

链式调用

跟语言没关系jq

# 链式调用在python中如何实现? 点多少次,其实还是对象本身
class A:
    # 每个函数返回self,把对象本身返回
    def test(self,name):
        self.name = name
        return self
    def test2(self,age):
        self.age = age
        return self
a =A()
x = a.test('小明').test2(18)
print(x.age)  # 18

# 每个函数返回self,把对象本身返回

bs4 其他用法

# limit 限制查找的个数

ret = soup.find_all(name='p',limit=1)
print(ret)      # [<p class="title"><b>The Dormouse's story</b></p>]

# recursive 是否递归查找

ret = soup.find_all(name='p',recursive=False)   # 只找同级的标签
ret = soup.find_all(name='p',recursive=True)    # 子孙的都找
print(ret)

3.css选择

# select 方法中写css选择器

ret = soup.select('.title')
ret = soup.select('#link1')     # 查找id为link1的标签

# 重点  > 与 空格 的区别  (>选择子元素,空格选择子孙中的)

ret = soup.select('.title>b')   # 查找class是title标签下的子元素b标签
ret = soup.select('.title b')   # 查找class是title标签下的子元素或子孙中的b元素


使用select提取出的元素如果是Tag标签,
可以使用属性a['herf'] 和名称提取,
还可以使用.string  .stripped_strings  .strings  .get_text()  获取内容

4.xpath选择(BeautifulSoup4没有xpath选择)

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。

XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。

因此,对 XPath 的理解是很多高级 XML 应用的基础。

代理池的搭建

# 收费: 稳定
    网站注册,向该网站的api接口发送请求,获取IP
    
    
    
# 免费:
    自己搭建:flask框架搭建服务,后台用爬虫(requests爬取免费),放入redis
      访问127.0.0.1/get 随机给一个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)

-超级鹰

-模拟登陆某些网站
-http://www.chaojiying.com/price.html
  # 注册用户
  # 创建软件
  # 充值
  # 下载demo
  # 修改demo,账号密码该上
  # 运行代码

-云打码

案例

爬取汽车之家新闻

# 爬取汽车之家新闻
# pip3 install beautifulsoup4
# pip3 install lxml
import requests

# 引入
from bs4 import BeautifulSoup


for i in range(1,10):

    ret = requests.get('https://www.autohome.com.cn/news/%s/#liststart'%i)
    ret.encoding = 'gbk'
    # print(ret.text)
    # 实例化得到对象(
    # 第一个参数,可以是字符串,或者是文件对象
    # 第二个参数,解析的方式(html.parser    lxml)
    soup = BeautifulSoup(ret.text, 'lxml')

    # 以后查找属性,都是操作soup这个对象
    # 查找文档树之查找所有
    # div=soup.find_all(name='div',id='auto-channel-lazyload-article')[0]
    # #查找div下的ul标签
    # ul=div.find_all(name='ul')
    # print(ul)
    # class是一个关键字
    ul = soup.find(name='ul', class_='article')
    # 找到ul下所有的li标签
    li_list = ul.find_all(name='li')
    # 循环列表
    for li in li_list:
        img = li.find(name='img')
        if img:
            # 获取标签的属性两种方式
            # img_ul=img['src']
            img_ul = 'http:' + img.attrs.get('src')
            title = li.find(name='h3').text
            desc = li.find('p').text
            url = 'http:' + li.find(name='a')['href']
            # print(img_ul)
            # print(title)
            # print(desc)
            # print(url)
            #图片保存
            img_name=img_ul.rsplit('/',1)[-1]
            ret2=requests.get(img_ul)
            with open(img_name,'wb') as f:
                for line in ret2.iter_content():
                    f.write(line)
            print('''
            文章标题:%s
            文章链接:%s
            文章图片地址:%s
            文章摘要:%s
            '''%(title,url,img_ul,desc))


#总结:bs4 查找文档树
# 标签对象=soup.find(name='div',href='',class_='')
# 标签对象可以继续使用find
# 获取属性两种方式   标签对象['属性名']   标签对象.attrs.get('属性名')
# 获取文本  标签对象.text
posted @ 2020-03-11 09:31  fwzzz  阅读(394)  评论(0编辑  收藏  举报