(小爬蟲,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