一天掌握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 任意空白字符(\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())

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

一天掌握python爬虫的更多相关文章

  1. Python 爬虫模拟登陆知乎

    在之前写过一篇使用python爬虫爬取电影天堂资源的博客,重点是如何解析页面和提高爬虫的效率.由于电影天堂上的资源获取权限是所有人都一样的,所以不需要进行登录验证操作,写完那篇文章后又花了些时间研究了 ...

  2. python爬虫成长之路(一):抓取证券之星的股票数据

    获取数据是数据分析中必不可少的一部分,而网络爬虫是是获取数据的一个重要渠道之一.鉴于此,我拾起了Python这把利器,开启了网络爬虫之路. 本篇使用的版本为python3.5,意在抓取证券之星上当天所 ...

  3. python爬虫学习(7) —— 爬取你的AC代码

    上一篇文章中,我们介绍了python爬虫利器--requests,并且拿HDU做了小测试. 这篇文章,我们来爬取一下自己AC的代码. 1 确定ac代码对应的页面 如下图所示,我们一般情况可以通过该顺序 ...

  4. python爬虫学习(6) —— 神器 Requests

    Requests 是使用 Apache2 Licensed 许可证的 HTTP 库.用 Python 编写,真正的为人类着想. Python 标准库中的 urllib2 模块提供了你所需要的大多数 H ...

  5. 批量下载小说网站上的小说(python爬虫)

    随便说点什么 因为在学python,所有自然而然的就掉进了爬虫这个坑里,好吧,主要是因为我觉得爬虫比较酷,才入坑的. 想想看,你可以批量自动的采集互联网上海量的资料数据,是多么令人激动啊! 所以我就被 ...

  6. python 爬虫(二)

    python 爬虫 Advanced HTML Parsing 1. 通过属性查找标签:基本上在每一个网站上都有stylesheets,针对于不同的标签会有不同的css类于之向对应在我们看到的标签可能 ...

  7. Python 爬虫1——爬虫简述

    Python除了可以用来开发Python Web之后,其实还可以用来编写一些爬虫小工具,可能还有人不知道什么是爬虫的. 一.爬虫的定义: 爬虫——网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区 ...

  8. Python爬虫入门一之综述

    大家好哈,最近博主在学习Python,学习期间也遇到一些问题,获得了一些经验,在此将自己的学习系统地整理下来,如果大家有兴趣学习爬虫的话,可以将这些文章作为参考,也欢迎大家一共分享学习经验. Pyth ...

  9. [python]爬虫学习(一)

    要学习Python爬虫,我们要学习的共有以下几点(python2): Python基础知识 Python中urllib和urllib2库的用法 Python正则表达式 Python爬虫框架Scrapy ...

  10. python爬虫学习(1) —— 从urllib说起

    0. 前言 如果你从来没有接触过爬虫,刚开始的时候可能会有些许吃力 因为我不会从头到尾把所有知识点都说一遍,很多文章主要是记录我自己写的一些爬虫 所以建议先学习一下cuiqingcai大神的 Pyth ...

随机推荐

  1. mac ci框架安装使用 memcached存session

    mac 安装memcached brew info memcached brew install memcached brew install memcached 安装过程具体不详细多讲 memcac ...

  2. linux 文件解锁

    //文件 sudo chmod 777 文件名 //文件夹内的文件 sudo chmod 777 文件夹/ * //遍历文件夹下的所有文件 sudo chmod -R 777 文件夹/ *

  3. react之传递数据的几种方式props传值、路由传值、状态提升、redux、context

    react之传递数据的几种方式 1.父子传值 父传值:<子的标签 value={'aaa'} index={'bbb'}></子的标签> 子接值:<li key={thi ...

  4. 解决eclipse/myeclipse导入项目时出现红色叹号的方法

  5. laravel创建资源路由控制器

    php artisan make:controller PhotoController --resource

  6. SQL优化过程中常见Oracle HINT

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  7. jstree使用新的

    1.首先准备jstree树的dom元素 <p id="flowList_ul" class="flowList_ul"></p> 2.初 ...

  8. windows剪贴板

    0x01  Windows剪贴板 Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制.Windows系统支持剪贴板IP ...

  9. Android开发---如何操作资源目录中的资源文件3--圆角边框、背景颜色渐变效果、边框颜色

    Android开发---如何操作资源目录中的资源文件3 效果图 1.圆角边框 2.背景颜色渐变效果 1.activity_main.xml 描述: 定义了一个shape资源管理按钮 <?xml ...

  10. spingmvc 访问静态文件,比如css,img等

    这里我来引用一段别人的原话 url-pattern有5种配置模式: (1)/xxx:完全匹配/xxx的路径 (2)/xxx/*:匹配以/xxx开头的路径,请求中必须包含xxx. (3)/*:匹配/下的 ...