一天掌握python爬蟲

一天掌握python爬蟲日記:

(小爬蟲,NO 咱們是大蜘蛛 )javascript

數據抓取:css

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 任意空白字符(\r  \n  \n)

# \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))

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

text = '\\n' # =>\n
# python \\\\n => \\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\tesseract.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())

===================================================================================
html

相關文章
相關標籤/搜索