• 一天掌握python爬虫


    一天掌握python爬虫日记:

    (小爬虫,NO 我们是大蜘蛛 )

    数据抓取:

    requests:
    requests 的底层实现其实就是 urllib
    开源地址:https://github.com/kennethreitz/requests
    中文文档 API: http://docs.python-requests.org/zh_CN/latest/index.html
    基本GET请求(headers参数 和 parmas参数):
    import requests

    url = "http://www.baidu.com"
    kw = {'wd': '爬虫'}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
    # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode()
    # res = requests.get(url=url, params=kw, headers=headers)
    # 也可以这么写
    res = requests.request(method="GET", url=url, params=kw, headers=headers)
    # print(res.text) # 查看响应内容,response.text 返回的是Unicode格式的数据
    print(res.content.decode("utf-8")) # 查看响应内容,response.content返回的字节流数据
    print(res.url)  # 查看完整url地址
    print(res.encoding)  # 查看响应头部字符编码
    print(res.status_code)  # 查看响应码

    StringIO与BytesIO:
    # StringIO在内存中读写str。
    # BytesIO 是在内存中读写bytes类型的二进制数据
    # 通过requests获取网络上图片的大小
    from io import BytesIO, StringIO
    from PIL import Image  # pip install pillow 安装

    img_url = "http://imglf1.ph.126.net/pWRxzh6FRrG2qVL3JBvrDg==/6630172763234505196.png"
    res = requests.get(img_url)
    f = BytesIO(res.content)
    img = Image.open(f)
    print(img.size)

    基本POST请求(data参数)
    import requests

    url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E5%8C%97%E4%BA%AC&needAddtionalResult=false'
    headers = {
        'User-Agent': 'User-Agent:Mozilla/5.0(Windows;U;WindowsNT6.1;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50',
        'Referer': 'https://www.lagou.com/jobs/list_python?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=',
        'Accept-Language': 'zh-Hans-CN,zh-Hans;q=0.5'
    }
    data = {
        'first': 'true',
        'kd': 'python',
        'pn': 1
    }
    resp = requests.post(url=url, data=data, headers=headers)
    # print(resp.content.decode('utf-8'))
    print(resp.json())  # # 如果是json文件可以直接显示,返回字典类型

    代理(proxies参数)
    proxies = {
        'http': '39.137.2.206:8080'

    }
    # 如果代理需要使用HTTP Basic Auth,可以使用下面这种格式:
    # proxy = { "http": "name:pass@61.158.163.130:16816" }
    res = requests.get("http://httpbin.org/ip", proxies=proxies)
    print(res.text)
    # {
    #   "origin": "39.137.2.206"
    # }
    也可以通过本地环境变量 HTTP_PROXY 和 HTTPS_PROXY 来配置代理:

    export HTTP_PROXY="http://39.137.2.206:8080"
    export HTTPS_PROXY="https://12.34.56.79:9527"


    web客户端验证

    如果是Web客户端验证,需要添加 auth = (账户名, 密码)

    import requests

    auth=('test', '123456')
    response = requests.get('http://192.168.199.107', auth = auth)
    print (response.text)


    Cookies:

    res = requests.get(url="http://www.baidu.com/")
    print(res.cookies)  # <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
    # print(res.cookies.get_dict()) # {'BDORZ': '27315'}
    cookiedict = requests.utils.dict_from_cookiejar(res.cookies)
    print(cookiedict)  # {'BDORZ': '27315'}


    session:

    url = 'http://www.renren.com/PLogin.do'
    headers = {
        'User-Agent': 'User-Agent:Mozilla/5.0(Windows;U;WindowsNT6.1;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50',
    }
    data = {
        # 'email': 'xxxx@qq.com',
        # 'password': 'xxxx'
    }
    session = requests.session()  # 创建session对象,可以保存Cookie值
    # 发送附带用户名和密码的请求,并获取登录后的Cookie值,保存在ssion里
    session.post(url=url, data=data, headers=headers)
    # session包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
    response = session.get("http://www.renren.com/410043129/profile")
    print(response.text)

    处理HTTPS请求 SSL证书验证:
    # 跳过证书验证,把 verify 设置为 False
    resp = requests.get('https://www.12306.cn/mormhweb/', verify=False)
    print(resp.content.decode('utf-8'))


    ==========================================================================================
    urllib库的基本使用:
    在 python2 中,urllib 被分为urllib,urllib2等

    request:

    from urllib import request

    # urlopen

    # res = request.urlopen(url='http://www.baidu.com')

    # print(res.read())  # 读取文件全部内容,返回字符串
    # print(res.readlines())
    # print(res.getcode()) # 200

    # Request执行更复杂的操作

    headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
    req = request.Request(url='http://www.baidu.com', headers=headers,method='GET')
    # 也可以通过调用Request.add_header() 添加/修改一个特定的header
    req.add_header("Connection", "keep-alive")
    # 也可以通过调用Request.get_header()来查看header信息
    print(req.get_header(header_name='Connection'))  # keep-alive
    res = request.urlopen(req)

    # print(res.read().decode())
    print(res.code)  # 可以查看响应状态码



    # parse
    from urllib import parse

    url = 'http://www.baidu.com/s?'
    wd = {'wd': '爬虫'}
    ps = parse.urlencode(wd)  # 通过urllib.urlencode()方法,将字典键值对按URL编码转换,从而能被web服务器接受
    url = url + ps
    print(url)  # http://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB

    url = parse.parse_qs(url)
    print(url)  # {'http://www.baidu.com/s?wd': ['爬虫']}
    # 通过parse.unquote方法,把 URL编码字符串,转换回原先字符串
    url = parse.unquote("wd=%E7%88%AC%E8%99%AB")
    print(url)  # wd=爬虫

    url = 'http://www.baidu.com/s;hello;123?wd=sss&name=qqq#a'
    result = parse.urlparse(url)
    print(result)
    # ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='hello;123', query='wd=sss&name=qqq', fragment='a')

    result2 = parse.urlsplit(url)
    print(result2)
    # SplitResult(scheme='http', netloc='www.baidu.com', path='/s;hello;123', query='wd=sss&name=qqq', fragment='a')


    # 处理HTTPS请求 SSL证书验证
    from urllib import request
    import ssl

    context = ssl._create_unverified_context()  # 表示忽略未经核实的SSL证书认证
    url = "https://www.12306.cn/mormhweb/"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

    req = request.Request(url, headers=headers)
    # 在urlopen()方法里 指明添加 context 参数
    res = request.urlopen(url=req, context=context)
    print(res.read().decode())

    Handler处理器 和 自定义Opener:

    from urllib import request

    # 构建一个HTTPHandler 处理器对象,支持处理HTTP请求
    # debuglevel=1参数,还会将 Debug Log 打开,程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来
    http_handler = request.HTTPHandler(debuglevel=1)
    # http_handler = request.HTTPSHandler() # 支持处理HTTPS请求
    # 调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
    opener = request.build_opener(http_handler)
    req = request.Request('http://www.baidu.com/')
    # 调用自定义opener对象的open()方法,发送request请求
    res = opener.open(req)
    print(res.code)


    ProxyHandler处理器(代理设置):

    from urllib import request
    httpproxy_handler = request.ProxyHandler({'http': '39.137.2.206:8080'})
    req = request.Request('http://httpbin.org/ip')
    opener = request.build_opener(httpproxy_handler)

    # res = opener.open(req) # 只有使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理
    # opener应用到全局
    request.install_opener(opener)
    res = request.urlopen(req)
    print(res.read())

    cookiejar库 和 HTTPCookieProcessor处理器:
    from http import cookiejar
    from urllib import request


    # 构建一个CookieJar对象实例来保存cookie
    # cookiejar = cookiejar.CookieJar()

    cookiejar = cookiejar.MozillaCookieJar('cookie.txt')

    cookiejar.load(ignore_discard=True)  # 读取 True 包括短暂性的cookie
    # 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象
    handler = request.HTTPCookieProcessor(cookiejar)
    opener = request.build_opener(handler)
    opener.open('http://www.baidu.com')

    # cookiejar.save(ignore_discard=True) # 保存

    cookieStr = ""
    for item in cookiejar:
        print(item.name+'='+item.value)


    urlretrieve:

    from urllib import request

    img_url = "http://n.sinaimg.cn/news/1_img/upload/cf3881ab/138/w1535h1003/20181029/MOVg-hnaivxq1076478.jpg"
    request.urlretrieve(img_url,filename='img.jpg')

    ================================================================================================

    数据提取:


    正则re模块:
    import re

    text = 'hello'
    # .匹配任意字符
    com = re.compile('.+')
    # match从头开始匹配
    ret = re.match(com, text)
    print(ret.group())
    # d匹配任意数字

    # D 匹配任意非数字

    # s 任意空白字符(     )

    # w a-z A-Z 数字 下划线

    # W  与w相反

    # [ ]组合,只要满足中括号中的某一项就算成功

    # ^[0-9] 非0-9 (脱字号)   ^a 以a开头

    # + 一个或多个

    # * 零个或多个

    # ? 零个或一个

    # {n} n个

    # {m,n} m-n个

    # $以  结尾

    # | 匹配多个字符或表达式

    # 贪婪模式(默认)  非贪婪模式
    text = '<h1>标题1</h1>'
    ret = re.match('<.+?>', text) # 非贪婪模式
    # ret = re.match('<.+>', text)
    print(ret.group())

    # 匹配0-100之间的数字
    text = '0'
    ret = re.match('[1-9]d?$|100$|0$', text)
    print(ret.group())

    # 转义字符
    text = 'apple price is $299'
    ret = re.search('$(d+)', text)
    print(ret.group(1))

    # 打印
    # text = '\n'
    text = r' '  # r原生的
    print(text)

    text = '\n' # =>
    # python \\n => \n
    # 正则 \n=>
    # ret = re.match('\\n', text)
    ret = re.match(r'\n', text)
    print(ret.group())


    # compile编译
    # pattern = re.compile('d+.?d+')
    # 多行
    pattern = re.compile("""
        d+
        .?
        d+
    """, re.VERBOSE)
    text = 'the number is 20.50'
    s = re.search(pattern, text)
    print(s.group())
    '''
    Pattern 对象的一些常用方法主要有:
            match 方法:从起始位置开始查找,一次匹配
            search 方法:从任何位置开始查找,一次匹配
            findall 方法:全部匹配,返回列表
            finditer 方法:全部匹配,返回迭代器
            split 方法:分割字符串,返回列表
            sub 方法:替换
    '''
    # match

    pattern = re.compile(r'd+')

    m = pattern.match('one123a', 3, 7)
    print(m)  # <_sre.SRE_Match object; span=(3, 6), match='123'>
    print(m.group())  # 123
    print(m.start())  # 3
    print(m.end())  # 6
    print(m.span())  # (3, 6) 返回匹配成功的整个子串的索引

    # search

    text = "apple's price $99,orange's price is $10"
    pattern = re.compile('.*($d+).*($d+)', re.I)  # # re.I 表示忽略大小写
    ret = pattern.search(text)
    # print(ret.group(0))   相当于print(ret.group())
    print(ret.group(1))
    print(ret.group(2))
    # 所有的组
    print(ret.groups())  # ('$99', '$10')
    print(ret.span())  # (0, 39) # 起始位置和结束位置

    # findall
    ret = re.findall('$d+', text)
    print(ret)  # ['$99', '$10']

    # finditer
    res = re.finditer('$d+', text)
    for m in res:
        print(m.group(), m.span())  # $99 (14, 17)  # $10 (36, 39)

    # split

    text1 = 'hello2world ni hao '
    ret = re.split(' |d', text1)  # 空格或数字
    print(ret)  # ['hello', 'world', 'ni', 'hao', '']

    # sub

    ret = re.sub('$d+', '0', text)
    print(ret)  # apple's price 0,orange's price is 0

    pattern = re.compile(r'(w+) (w+)')  # [A-Za-z0-9]
    s = 'a b,c d'
    res = pattern.sub('123', s)
    print(res)  # 123,123
    res = pattern.sub(r'2 1', s)  # 引用分组
    print(res)  # b a,d c

    print(pattern.sub(lambda m: m.group(2) + m.group(1), s))  # ba,dc
    print(pattern.sub(lambda m: m.group(2) + m.group(1), s, 1))  # ba,c d  # 最多替换一次

    # 匹配中文

    title = '你好,hello,世界'
    pattern = re.compile(r'[u4e00-u9fa5]+')
    result = pattern.findall(title)

    print(result)  # ['你好', '世界']

    =======================================================================================
    XPath 开发工具

        开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)
        Chrome插件 XPath Helper
        Firefox插件 try XPath


    最常用的路径表达式:
    表达式     描述
    nodename     选取此节点的所有子节点。
    /     从根节点选取。
    //     从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
    .     选取当前节点。
    ..     选取当前节点的父节点。
    @     选取属性。


    lxml库:

    lxml 是 一个HTML/XML的解析器,主要的功能是如何解析和提取 HTML/XML 数据。
    lxml python 官方文档:http://lxml.de/index.html

    '''
    最常用的路径表达式:
    表达式     描述
    nodename     选取此节点的所有子节点。
    /     从根节点选取。 子元素
    //     从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
    .     选取当前节点。
    ..     选取当前节点的父节点。
    @     选取属性。

    路径表达式     结果
    /bookstore/book[1]     选取属于 bookstore 子元素的第一个 book 元素。
    /bookstore/book[last()]     选取属于 bookstore 子元素的最后一个 book 元素。
    /bookstore/book[last()-1]     选取属于 bookstore 子元素的倒数第二个 book 元素。
    /bookstore/book[position()<3]     选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
    //title[@lang]     选取所有拥有名为 lang 的属性的 title 元素。
    //title[@lang=’eng’]     选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。

    /text() 文本内容
    //input[starts-with(@name,'name1')]     查找name属性中开始位置包含'name1'关键字的页面元素
    //input[contains(@name,'na')]         查找name属性中包含na关键字的页面元素

    通配符     描述
    *     匹配任何元素节点。
    @*     匹配任何属性节点。
    '''
    # lxml

    from lxml import etree

    text = '''
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-inactive"><a href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此处缺少一个 </li> 闭合标签
         </ul>
     </div>
     
    '''

    # html = etree.HTML(text)  # 利用etree.HTML,将字符串解析为HTML文档
    # res = etree.tostring(html)  # 按字符串序列化HTML文档
    # print(res) # lxml 可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签
    # print(type(html)) # <class 'lxml.etree._Element'>  # 显示etree.parse() 返回类型

    # parser = etree.HTMLParser(encoding='utf-8')
    # html = etree.parse(source='tencent.html', parser=parser)  # 读取外部文件
    # print(etree.tostring(html, pretty_print=True))  # 美观的打印

    # 实例测试

    html = etree.HTML(text)
    res = html.xpath('//li/@class')  # 获取<li> 标签的所有 class属性
    print(res)  # ['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
    res = html.xpath('//li/a[@href="link1.html"]')  # 获取<li>标签下hre 为 link1.html 的 <a> 标签
    print(res)  # [<Element a at 0x7ff5a1409388>]
    res = html.xpath('//li/a/@href')  # 获取 <li> 标签下的<a>标签里的所有 class
    print(res)  # ['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
    res = html.xpath('//li[last()]/a/@href')  # 获取最后一个 <li> 的 <a> 的 href
    print(res)  # ['link5.html']
    res = html.xpath('//li[last()-1]/a/@href')  # 倒数第二个 <li> 的 <a> 的 href
    print(res)  # ['link4.html']

    res = html.xpath('//li[position()>1 and position()<3]/a/text()')
    print(res)  # ['second item']

    res = html.xpath('//li[contains(@class,"inactive")]/a/text()')  # 包含
    print(res)  # ['third item']

    res = html.xpath('//li/a[starts-with(@href,"link5")]/text()')  # 开头
    print(res)  # ['fifth item']

    ==================================================================
    JsonPath

    """
    JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具
        官方文档:http://goessner.net/articles/JsonPath

    XPath     JSONPath     描述
    /     $     根节点
    .     @     现行节点
    /     .or[]     取子节点
    ..     n/a     取父节点,Jsonpath未支持
    //     ..     就是不管位置,选择所有符合条件的条件
    *     *     匹配所有元素节点
    @     n/a     根据属性访问,Json不支持,因为Json是个Key-value递归结构,不需要。
    []     []     迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等)
    |     [,]     支持迭代器中做多选。
    []     ?()     支持过滤操作.
    n/a     ()     支持表达式计算
    ()     n/a     分组,JsonPath不支持
    """
    import requests
    import jsonpath
    import json

    url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
    res = requests.get(url=url)
    html = res.text

    jsonobj = json.loads(html)  # 把json格式字符串转换成python对象
    citylist = jsonpath.jsonpath(jsonobj, '$..name')  # 从根节点开始,匹配name节点

    # print(citylist) # ['安庆', '澳门特别行政区', '鞍山',
    # print(type(citylist)) # <class 'list'>
    content = json.dumps(citylist, ensure_ascii=False)
    # print(content) # ["安庆", "澳门特别行政区", "鞍山",
    with open('city.json', 'w') as f:
        f.write(content)
    ==========================================================
    """
    lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
    官方文档:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0
    Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

        Tag  HTML 中的一个个标签,有两个重要的属性,是 name 和 attrs
        NavigableString 标签的内容
        BeautifulSoup 表示的是一个文档的内容
        Comment 注释内容,其输出的内容不包括注释符号

    """
    from bs4 import BeautifulSoup

    html = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title" name="dromouse"><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, 'lxml')  # 指定lxml解析器。
    # soup = BeautifulSoup(open('tencent.html'),'lxml') # 打开本地 HTML 文件的方式来创建对象
    # print(soup.prettify())  # 格式化输出 soup 对象的内容

    # Tag

    # print(soup.name) # [document] #soup 对象本身比较特殊,它的 name 即为 [document]
    # print(soup.head.name) # head #对于其他内部标签,输出的值便为标签本身的名称
    # print(soup.p.attrs) # {'class': ['title'], 'name': 'dromouse'}
    # print(soup.p['class']) # ['title']
    # print(soup.p.get('class')) # ['title']
    # soup.p['class'] = "newClass"
    # print(soup.p) # 可以对这些属性和内容等等进行修改
    # del soup.p['class'] # 对这个属性进行删除
    # print(soup.p)

    # NavigableString
    # print(soup.p.string)  # The Dormouse's story
    # print(type(soup.p.string))  # <class 'bs4.element.NavigableString'>

    # BeautifulSoup
    # print(type(soup))  # <class 'bs4.BeautifulSoup'>
    # print(soup.attrs)  # {} # 文档本身的属性为空

    # Comment
    # print(soup.a.string)  # Elsie
    # print(type(soup.a.string))  # <class 'bs4.element.Comment'>

    # 遍历文档树
    '''

    # 直接子节点 :.contents .children 属性.content
    print(soup.head.contents) # [<title>The Dormouse's story</title>]
    print(soup.head.children) # <list_iterator object at 0x7f4a07c70240>
    for child in soup.body.children:
        print(child)

    # 所有子孙节点: .descendants 属性,递归循环
    for child in soup.descendants:
        print(child)

    # 节点内容: .string 属性
    print(soup.title.string)  # The Dormouse's story
    '''
    # 搜索文档树
    # find_all(name, attrs, recursive, text, **kwargs)
    # print(soup.find_all('b')) # 传字符串 # 查找文档中所有的<b>标签:
    # import re
    # print(soup.find_all(re.compile('^b')))
    # print(soup.find_all(['a','b'])) # 文档中所有<a>标签和<b>标签:
    # print(soup.find_all('a',limit=2)) # 提取2个

    # print(soup.find_all('p', attrs={'class': 'title'}))
    # print(soup.find_all('p', class_='title'))
    # print(soup.find_all('p'))
    # print(list(soup.find_all('p')[1].stripped_strings)) # 去空格
    # print(list(soup.find_all('p')[1].strings))  # 内容
    # print(soup.find_all('p')[0].string)  # 节点内容 是一个生成器
    # print(type(soup.find_all('p')[1].get_text()))  # 内容 # <class 'str'>

    # print(soup.find_all(text='Lacie')) # ['Lacie'] #  搜文档中的字符串内容

    # CSS选择器
    # CSS时,标签名不加任何修饰,类名前加.,id名前加  #
    # print(soup.select('title')) # [<title>The Dormouse's story</title>]
    # print(soup.select('.sister'))
    # print(soup.select('#link1'))
    # print(soup.select('p #link1')) # 查找 p 标签中,id 等于 link1的内容,二者需要用空格分开
    # print(soup.select('head > title')) # 直接子标签查找,则使用 > 分隔
    # print(soup.select('a[class="sister"]'))
    # print(soup.select('p a[href="http://example.com/elsie"]'))

    # print(soup.select('title')[0].get_text())  # The Dormouse's story
    # print(soup.select('title')[0].string)  # The Dormouse's story
    # print(soup.select('title')[0].stripped_strings)  # <generator object stripped_strings at 0x7f01587f8620>
    # print(soup.select('title')[0].strings)  # <generator object _all_strings at 0x7f71966fd620>

    ===============================================================
    多线程:

    import threading
    import time


    def coding():
        for i in range(3):
            print('{}在写代码{}'.format(threading.current_thread(), i))
            time.sleep(1)


    def drawing():
        for i in range(3):
            print('{}在写绘画{}'.format(threading.current_thread(), i))
            time.sleep(1)


    def main():
        threading.Thread(target=coding).start()
        threading.Thread(target=drawing).start()
        print(threading.enumerate())  # 所有线程枚举


    class CodingThread(threading.Thread):
        def run(self):
            for i in range(3):
                print('{}在写代码{}'.format(threading.current_thread(), i))
                time.sleep(1)


    class DrawingThread(threading.Thread):
        def run(self):
            for i in range(3):
                print('{}在写绘画{}'.format(threading.current_thread(), i))
                time.sleep(1)


    def main1():
        CodingThread().start()
        DrawingThread().start()


    if __name__ == '__main__':
        # main()
        main1()


    # 修改全局变量

    VALUE = 0
    gLock = threading.Lock()


    def add():
        global VALUE
        gLock.acquire()  # 加锁
        for i in range(100000):
            VALUE += 1
        gLock.release()  # 解锁
        print("value:{}".format(VALUE))


    def main():
        for i in range(2):
            t = threading.Thread(target=add)
            t.start()


    if __name__ == '__main__':
        main()

    '''
    Queue,是线程安全的
        初始化: class Queue.Queue(maxsize) FIFO 先进先出
        包中的常用方法:
            Queue.qsize() 返回队列的大小
            Queue.empty() 如果队列为空,返回True,反之False
            Queue.full() 如果队列满了,返回True,反之False
            Queue.full 与 maxsize 大小对应
            Queue.get([block[, timeout]])获取队列,timeout等待时间
        Queue.task_done() #向队列中已完成的元素发送join信号
        创建一个“队列”对象
            import Queue
            myqueue = Queue.Queue(maxsize = 10)
        将一个值放入队列中
            myqueue.put(10)
        将一个值从队列中取出
            myqueue.get()
    '''
    from queue import Queue

    q = Queue(maxsize=4)
    print(q.maxsize)  # 4
    print(q.empty())  # True
    q.put(1, block=True)  # 默认True
    q.put(2)
    print(q.qsize())  # 2
    q.put(3)
    q.put(4)
    print(q.full())  # True
    print(q.get(block=True))  # 1 # 默认True

    多线程任务:

    import threading
    import time
    from queue import Queue

    DOCS = ""


    class ThreadSpider(object):
        def __init__(self):
            self.url_queue = Queue()
            self.html_queue = Queue()

        def get_total_url(self):
            for i in range(10):
                self.url_queue.put(i)

        def parse_url(self):
            while self.url_queue.not_empty:   # 一个人任务添加到队列
                url = self.url_queue.get()
                time.sleep(1)
                self.html_queue.put(url)
                # 向任务已经完成的队列发送一个信号
                # 主要是给join用的,每次get后需要调用task_done,直到所有任务都task_done,join才取消阻塞
                self.url_queue.task_done()

        def save(self):
            while self.html_queue.not_empty:
                html = self.html_queue.get()
                time.sleep(1)
                global DOCS
                DOCS += str(html)+' '
                self.html_queue.task_done()

        def run(self):
            thread_list = []
            thread_url = threading.Thread(target=self.get_total_url)
            thread_list.append(thread_url)

            for i in range(10):
                thread_parse = threading.Thread(target=self.parse_url)
                thread_list.append(thread_parse)

            thread_save = threading.Thread(target=self.save)
            thread_list.append(thread_save)

            for t in thread_list:
                t.setDaemon(True) # 为每个进程设置为后台进程,效果是主进程退出子进程也会退出,解决程序结束无法退出的问题
                t.start()

            self.url_queue.join()  # 主线程等待子线程
            self.html_queue.join()


    if __name__ == '__main__':
        ThreadSpider().run()
        print(DOCS)

    多线程任务2:

    DOCS = ""


    class ProThread(threading.Thread):
        def __init__(self, url_queue, html_queue, *args, **kwargs):
            super(ProThread, self).__init__(*args, **kwargs)
            self.url_queue = url_queue
            self.html_queue = html_queue

        def run(self):
            while True:
                if self.url_queue.empty():
                    break
                url = self.url_queue.get()
                self.parse_url(url)

        def parse_url(self, url):
            time.sleep(1)
            self.html_queue.put(url)
            self.url_queue.task_done()


    class ConThread(threading.Thread):
        def __init__(self, url_queue, html_queue, *args, **kwargs):
            super(ConThread, self).__init__(*args, **kwargs)
            self.url_queue = url_queue
            self.html_queue = html_queue

        def run(self):
            while True:
                if self.html_queue.empty() and self.url_queue.empty():
                    break
                html = self.html_queue.get()
                global DOCS
                DOCS += str(html)+' '
                self.html_queue.task_done()


    def main():
        url_queue = Queue(100)
        html_queue = Queue(1000)
        for i in range(10):
            url_queue.put(i)

        for i in range(5):
            t = ProThread(url_queue, html_queue)
            t.setDaemon(True)
            t.start()
        for i in range(5):
            t = ConThread(url_queue, html_queue)
            t.setDaemon(True)
            t.start()
        url_queue.join()
        html_queue.join()


    if __name__ == '__main__':
        main()
        print(DOCS)

    =======================================================================================
    Selenium:

    '''
    Selenium是一个Web的自动化测试工具
    Selenium 官方参考文档:http://selenium-python.readthedocs.io/index.html

    chromedriver:http://chromedriver.storage.googleapis.com/index.html
    查看driver和浏览器版本:http://chromedriver.storage.googleapis.com/2.31/notes.txt
    geckodriver:https://github.com/mozilla/geckodriver/releases

    chmod +x chromedriver
    sudo mv chromedriver /usr/bin/
    #解压,加上执行权限,移动到/usr/bin/文件夹下。(复制则将mv改为cp)

    PhantomJS 曾经的知名无头浏览器
    '''
    import time
    from selenium import webdriver

    # 调用键盘按键操作时需要引入的Keys包
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By

    # driver = webdriver.Firefox(executable_path=r'xx/geckodriver') # 填写驱动的位置
    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')  # chrome一样的设置
    driver = webdriver.Firefox(options=options)  # 已在环境变量指定

    driver.get('http://www.baidu.com')  # get方法会一直等到页面被完全加载,然后才会继续程序
    # print(driver.page_source) # 打印页面内容
    # data = driver.find_element_by_id('wrapper').text  # 获取页面名为 wrapper的id标签的文本内容
    # print(data)
    # print(driver.title)  # 打印页面的标题 百度一下,你就知道
    # driver.save_screenshot('baidu.png')  # 生成当前页面快照并保存
    # driver.find_element_by_id('kw').send_keys(u'爬虫')

    # driver.find_element(By.ID, value='kw').send_keys(u'爬虫')
    # driver.find_element_by_id('su').click() # 模拟点击
    # driver.save_screenshot('爬虫.png')


    # driver.find_element_by_id('kw').clear() # 清除输入框内容
    driver.find_element(By.ID, value='kw').send_keys(u'长城')
    driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')# ctrl+a 全选输入框内容
    driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')# ctrl+x 剪切输入框内容
    driver.find_element_by_id('kw').clear() # 清除输入框内容
    driver.find_element_by_id('kw').send_keys(Keys.CONTROL,'v')# 粘贴
    driver.find_element_by_id('su').send_keys(Keys.RETURN) # 模拟Enter回车键
    time.sleep(3)
    driver.save_screenshot('长城.png')
    print(driver.current_url) # 获取当前url
    # print(driver.get_cookies()) # 获取当前页面Cookie
    driver.close()
    driver.quit()


    """
    Selenium 的 WebDriver提供了各种方法来寻找元素

    <input type="text" name="user-name" id="passwd-id" />
    # 获取id标签值 By ID
    element = driver.find_element_by_id("passwd-id")
    # 获取name标签值 By Name
    element = driver.find_element_by_name("user-name")
    # 获取标签名值 By Tag Name
    element = driver.find_elements_by_tag_name("input")
    # 也可以通过XPath来匹配 By XPath
    element = driver.find_element_by_xpath("//input[@id='passwd-id']")
    # By Class Name
    <div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div>
    cheeses = driver.find_elements_by_class_name("cheese")
    # By Link Text
    <a href="http://www.google.com/search?q=cheese">cheese</a>
    cheese = driver.find_element_by_link_text("cheese")
    # By Partial Link Text
    <a href="http://www.google.com/search?q=cheese">search for cheese</a>
    cheese = driver.find_element_by_partial_link_text("cheese")
    # By CSS
    <div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>
    cheese = driver.find_element_by_css_selector("#food span.dairy.aged")

    获取元素的属性值:
    submitBtn=driver.find_element_by_id('su')
    print(type(submitBtn))
    # <class 'selenium.webdriver.firefox.webelement.FirefoxWebElement'>
    print(submitBtn.get_attribute('value'))# 百度一下

    鼠标动作链:
    #导入 ActionChains 类
    from selenium.webdriver import ActionChains

    # 鼠标移动到 ac 位置
    ac = driver.find_element_by_xpath('element')
    ActionChains(driver).move_to_element(ac).perform() # perform执行 比如遇到下拉框要先移动到具体位置再点击


    # 在 ac 位置单击
    ac = driver.find_element_by_xpath("elementA")
    ActionChains(driver).move_to_element(ac).click(ac).perform()

    # 在 ac 位置双击
    ac = driver.find_element_by_xpath("elementB")
    ActionChains(driver).move_to_element(ac).double_click(ac).perform()

    # 在 ac 位置右击
    ac = driver.find_element_by_xpath("elementC")
    ActionChains(driver).move_to_element(ac).context_click(ac).perform()

    # 在 ac 位置左键单击hold住
    ac = driver.find_element_by_xpath('elementF')
    ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform()

    # 将 ac1 拖拽到 ac2 位置
    ac1 = driver.find_element_by_xpath('elementD')
    ac2 = driver.find_element_by_xpath('elementE')
    ActionChains(driver).drag_and_drop(ac1, ac2).perform()

    # 导入 Select 类
    from selenium.webdriver.support.ui import Select

    填充表单:
    select.select_by_index(1) # index 索引从 0 开始
    select.select_by_value("0") # value是option标签的一个属性值,并不是显示在下拉框中的值
    select.select_by_visible_text(u"客户端") # visible_text是在option标签文本的值,是显示在下拉框的值
    select.deselect_all() 全取消
    弹窗处理:
    alert = driver.switch_to_alert()
    页面切换:
    driver.switch_to.window("this is window name")
    使用 window_handles 方法来获取每个窗口的操作对象:
    for handle in driver.window_handles:
        driver.switch_to_window(handle)

    页面前进和后退:
    driver.forward()     #前进
    driver.back()        # 后退
    Cookies

    获取页面每个Cookies值:
    for cookie in driver.get_cookies():
        print "%s -> %s" % (cookie['name'], cookie['value'])
    删除Cookies
    # By name
    driver.delete_cookie("CookieName")
    # all
    driver.delete_all_cookies()
    隐式等待

    隐式等待比较简单,就是简单地设置一个等待时间,单位为秒,等待时间后找不到,抛异常。

    from selenium import webdriver

    driver = webdriver.Chrome()
    driver.implicitly_wait(10) # seconds
    driver.get("http://www.xxxxx.com/loading")
    myDynamicElement = driver.find_element_by_id("myDynamicElement")
    当然如果不设置,默认等待时间为0。

    显式等待
    显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    # WebDriverWait 库,负责循环等待
    from selenium.webdriver.support.ui import WebDriverWait
    # expected_conditions 类,负责条件出发
    from selenium.webdriver.support import expected_conditions as EC

    driver = webdriver.Chrome()
    driver.get("http://www.xxxxx.com/loading")
    try:
        # 页面一直循环,直到 id="myDynamicElement" 出现
        element = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "myDynamicElement"))
        )
    finally:
        driver.quit()

    如果不写参数,程序默认会 0.5s 调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。
    一些内置的等待条件:
    title_is  检查页面标题的期望
    title_contains 标题包含
    presence_of_element_located # 某个元素加载进来
    visibility_of_element_located # 元素是否存在于一个页面和可见
    visibility_of
    url_to_be(url) 当前的url是否是url
    presence_of_all_elements_located
    text_to_be_present_in_element
    text_to_be_present_in_element_value((By.id,'xxx'),'yyy')  xxx的内容是否是yyy  
    frame_to_be_available_and_switch_to_it
    invisibility_of_element_located
    element_to_be_clickable  是否可点击
    staleness_of
    element_to_be_selected
    element_located_to_be_selected
    element_selection_state_to_be
    element_located_selection_state_to_be
    alert_is_present
    """

    鼠标示例:

    import time
    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains

    option = webdriver.FirefoxOptions()
    option.add_argument('-headless')
    driver = webdriver.Firefox(options=option)
    driver.get('http://www.baidu.com')

    inputTag = driver.find_element_by_id('kw')
    submitBtn = driver.find_element_by_id('su')

    actions = ActionChains(driver)
    actions.move_to_element(inputTag)
    actions.send_keys_to_element(inputTag,'abc')
    actions.move_to_element(submitBtn)
    actions.click(submitBtn)
    actions.perform() # 执行上面的动作
    time.sleep(3)
    driver.save_screenshot('abc.png')
    driver.close()
    driver.quit()

    cookie示例:

    from selenium import webdriver

    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')
    driver = webdriver.Firefox(options=options)
    driver.get('http://www.baidu.com/')
    for cookie in driver.get_cookies():
        print(cookie['name']+'='+cookie['value'])

    print('+'*30)
    print(driver.get_cookie('BD_UPN'))
    driver.delete_cookie('BD_UPN')
    print(driver.get_cookie('BD_UPN'))
    driver.delete_all_cookies()

    driver.close()
    driver.quit()

    等待的示例:
    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By

    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')
    driver = webdriver.Firefox(options=options)
    driver.get('http://www.baidu.com/')

    # 隐式等待,等待时间后找不到,抛异常
    # driver.implicitly_wait(5)
    # driver.find_element_by_id('abcd')
    # 显式等待
    WebDriverWait(driver,5).until(
        # 某个元素加载进来
        EC.presence_of_all_elements_located((By.ID,'abcd'))
    )

    driver.close()
    driver.quit()

    调用js示例:

    from selenium import webdriver
    import time

    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')
    driver = webdriver.Firefox(options=options)
    # driver.get('http://www.baidu.com/')
    # driver.execute_script('window.open("http://www.dpuban.com")')

    # print(driver.window_handles)  # 获取每个窗口的操作对象
    # driver.switch_to.window(driver.window_handles[0])  # 页面切换
    # print(driver.current_url)

    # driver.get("https://movie.douban.com/typerank?type_name=剧情&type=11&interval_id=100:90&action=")
    # time.sleep(5)
    # driver.execute_script('document.documentElement.scrollTop=10000') # 向下滚动10000像素
    # time.sleep(5)
    # driver.save_screenshot('douban.png')

    driver.get("https://www.baidu.com/")
    # 给搜索输入框标红的javascript脚本
    # js = 'var q=document.getElementById("kw");q.style.border="2px solid red";'
    # driver.execute_script(js)
    # driver.save_screenshot("redbaidu.png")
    # js隐藏元素,将获取的图片元素隐藏
    img = driver.find_element_by_xpath("//*[@id='lg']/img")
    driver.execute_script('$(arguments[0]).fadeOut()', img)
    time.sleep(5)
    # 向下滚动到页面底部
    # driver.execute_script("$('.scroll_top').click(function(){$('html,body').animate({scrollTop: '0px'}, 800);});")
    driver.save_screenshot("nullbaidu.png")

    driver.close()
    driver.quit()

    设置代理示例:

    from selenium import webdriver
    from selenium.webdriver.common.proxy import Proxy,ProxyType

    proxy=Proxy({
        'proxyType': ProxyType.MANUAL,   # 手动设置
        'httpProxy': '61.183.233.6:54896',
        'noProxy': ''
    })
    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')
    driver = webdriver.Firefox(options=options,proxy=proxy)
    driver.get('http://httpbin.org/ip')
    print(driver.page_source)

    ============================================================================================

    """
    Tesseract
    Tesseract 是一个 OCR 库,目前由 Google 赞助(Google 也是一家以 OCR 和机器学习技术闻名于世的公司)。Tesseract 是目前公认最优秀、最精确的开源 OCR 系统,除了极高的精确度,Tesseract 也具有很高的灵活性。它可以通过训练识别出任何字体,也可以识别出任何 Unicode 字符。
    安装Tesseract
    Windows 系统
    下载可执行安装文件https://code.google.com/p/tesseract-ocr/downloads/list安装。
    Linux 系统
    可以通过 apt-get 安装: $sudo apt-get install tesseract-ocr
    # 安装训练数据(equ为数学公式包)
    sudo apt-get install tesseract-ocr-eng tesseract-ocr-chi-sim  tesseract-ocr-equ
    Mac OS X系统
    用 Homebrew(http://brew.sh/)等第三方库可以很方便地安装 brew install tesseract
    安装pytesseract
    Tesseract 是一个 Python 的命令行工具,不是通过 import 语句导入的库。安装之后,要用 tesseract 命令在 Python 的外面运行
    pip install pytesseract

    tesseract --list-langs可以查看当前支持的语言,chi_sim表示支持简体中文
    tesseract -l chi_sim paixu.png paixu
    """
    '''

    import pytesseract
    from PIL import Image

    image = Image.open('a.png')
    text = pytesseract.image_to_string(image)
    print(text)


    from PIL import Image
    import pytesseract

    # 设置tesseract的位置
    # pytesseract.pytesseract.tesseract_cmd = r'E:Program Files (x86)Tesseract-OCR esseract.exe'
    image=Image.open('b.png')
    # 设置识别语言库
    text=pytesseract.image_to_string(image, lang='chi_sim')
    print(text)


    from PIL import Image
    import subprocess

    image = Image.open('b.png')
    subprocess.call(['tesseract', '-l', 'chi_sim', 'b.png', 'zhongwen']) #前三个参赛执行的命令, b.png要识别的图片,zhongwen保存的txt文件名

    with open('zhongwen.txt', 'r') as f:
        print(f.read())
    '''

    from PIL import Image
    import subprocess

    image = Image.open('b.png')
    # 对图片进行阈值过滤(低于143的置为黑色,否则为白色)
    image = image.point(lambda x: 0 if x < 143 else 255)
    # 重新保存图片
    image.save('b1.png')
    # 调用系统的tesseract命令对图片进行OCR识别
    # subprocess.call(["tesseract", 'a1.png', "output"])
    subprocess.call(['tesseract', '-l', 'chi_sim', 'b1.png', 'zhongwen'])
    # 打开文件读取结果
    with open("zhongwen.txt", 'r') as f:
        print(f.read())

    ===================================================================================

  • 相关阅读:
    解决无法安装Microsoft .Net Framework 3.5
    day11-15,装饰器
    Xmanager Power Suit 6.0.0009 最新版注册激活
    eth
    MySql 8.0 版本使用navicat连不上解决
    day11
    Mybatis使用规则
    nginx的基本配置
    Mybatis分页插件PageHelper使用
    dubbo的使用
  • 原文地址:https://www.cnblogs.com/fly-book/p/10135616.html
Copyright © 2020-2023  润新知