上药三品,神与气精

曾因酒醉鞭名马 生怕情多累美人


  • 首页

  • 关于

  • 分类

  • 标签

  • 归档

  • 搜索

python之数据结构

发表于 2016-05-16 | 阅读次数:
字数统计: 2.6k | 阅读时长 ≈ 10

对于一门语言来说,数据结构是其所有精华的所在,是python开发的基础。对于很多新人来说,就是觉得挺简单的,实际上手还是较困难。

python这里介绍四种数据结构:
1.元组
2.列表
3.字典
4.序列

元组

tuple是由一系列元素组成的ds,所有元素被包含在一对圆括号中。创建元组时,可以不指定元素个数,但是一旦创建之后,就不能进行任何修改。
这里需要注意一下,如果创建的元组只包含一个元素,通常会忽略单元素后的逗号。正确写法如下:

tuple = (apple,)
print (tuple[0])
print (type(tuple))

这段代码定义了一个单元素的tuple“apple”,并且类型为。

元组,列表,字典等都是从0开始的,[0]获取的就是第一个元素。

元组创建之后,不能进行修改,也不能进行赋值操作。

元组可以进行负数索引,分片索引,另外元组还可以由其他元组组成,就成了二元元组。

元组的遍历
这里介绍下二元元组的遍历。

for i in tuple:
    for j in i:
        print(j)

##列表

列表是方括号。

列表可以实现添加 删除 查找等操作,元素的值可以被修改。

添加使用append()
还可以考虑insert(),不过insert要指明位置。
删除直接用remove()
pop()是取出最后一个元素。
列表的使用和元组十分相似,支持负数索引 分片还有多元列表等特性,但是列表中的元素可以进行修改。

列表还可以进行连接操作。一种是extend()连接两个不同的列表,另外一种是使用运算符“+”或“+=”。

list = ["apple","banana","orange","grape"]  
print(list.index("grape"))  
print("orange" in list)

打印索引,
判断orange是否在列表中。

列表排序和反转

list.sort()
list.reverse()  

sort()这个函数,需要仔细说明下,sort(cmp,key=None,reverse=False)

在这和大家分享一下机器学习里的一个案例,看看列表的操作。

统计 Python 中的字数
问题
在 Python 中实施函数“count_words()”,该函数将字符串“s”和数字“n”用作输入,并返回“s”中“n”个出现频率最高的单词。返回值应该是一个元组列表 - 出现频率最高的“n”个单词及其相应的出现次数“[(, ), (, ), …]”,按出现次数的降序排列。
您可以假设所有输入都是小写形式,并且不含标点符号或其他字符(只包含字母和单个分隔空格)。如果出现次数相同,则按字母顺序排列出现次数相同的单词。
例如:

print count_words("betty bought a bit of butter but the butter was bitter",3)

Output:

[('butter', 2), ('a', 1), ('betty', 1)]
  """Count words."""
from collections import Counter
from operator import itemgetter
def count_words(s, n):
    """Return the n most frequently occuring words in s."""
    cnt = Counter()
    for word in s.split(" "):
        cnt[word] += 1
    a = cnt.items()
    b = sorted(a,key=lambda a:a[0],reverse=False)
    c = sorted(b,key=itemgetter(1),reverse=True)
    top_n = c[0:n]
    # TODO: Count the number of occurences of each word in s

    # TODO: Sort the occurences in descending order (alphabetically in case of ties)

    # TODO: Return the top n words as a list of tuples (<word>, <count>)
    return top_n


def test_run():
    """Test count_words() with some inputs."""
    print count_words("cat bat mat cat bat cat", 3)
    print count_words("betty bought a bit of butter but the butter was bitter", 3)


if __name__ == '__main__':
    test_run()

如何来分析这个案例呢?

首先是定义一个字符串

s=“betty bought a bit of butter but the butter was bitter”

接着使用文档中提到的collections来处理这个统计

from collections import Counter
cnt = Counter()
for word in s.split(" "):
    cnt[word] += 1

这里处理完之后,需要停下来检查一下cnt是啥类型
class ‘collections.Counter’

Counter({'butter': 2, 'a': 1, 'bitter': 1, 'of': 1, 'but': 1, 'betty': 1, 'bit': 1, 'was': 1, 'the': 1, 'bought': 1})

这个形式应该就是我们后续要介绍的dict字典类型,我们需要把它转换为列表

cnt.items()

转换了之后,我们还需要做哪些处理呢?

[('a', 1), ('butter', 2), ('bitter', 1), ('of', 1), ('but', 1), ('betty', 1), ('bit', 1), ('was', 1), ('the', 1), ('bought', 1)]   

看看题目的要求,统计次数多的在前,一是数值大的要靠前站;
另外就是数值一样,按照字典顺序,a-z这种排列一下。

这里我就考虑使用这种顺序尝试一下咯。

先根据字典顺序,排列一下

sorted(a,key=lambda a:a[0],reverse=False)

这个是正常的升序排列,得到结果:

[('a', 1), ('betty', 1), ('bit', 1), ('bitter', 1), ('bought', 1), ('but', 1), ('butter', 2), ('of', 1), ('the', 1), ('was', 1)]

接下来就是把数值大的调到前面去,也就是比较一下第二个值,按照降序排列处理一下

from operator import itemgetter
sorted(b,key=itemgetter(1),reverse=True)

这样就基本实现了对列表里的排序,接着分片处理下就达到了题目要求。

这个方案是我的初步方案,可能不是最简便的,供大家参考下,嘻嘻。

列表还有一个操作就是实现堆栈和队列,这个在大学的数据结构课程有简单接触的,问题就是很多只知道大概了啊。。

堆栈就是后进先出

队列则是先进先出
使用列表的append()和pop()操作可以模拟这两个数据结构
append()可以把一个元素添加到堆栈的顶部,
pop()把堆栈的最后一个元素弹出来。

队列的不同之处在于弹出时参数设置不一样,
pop(-1)弹出第一个元素

##字典

字典也是较为常见的,也是比较的重要的数据结构。key-value这种键值对,也是数据库的一种基本模式。

字典是花括号{}

这里需要注意一下,键是区分大小写的。一般而言,创建字典时,可以使用数字作为索引。
键值对这种结构,

value=dict[key]

说下字典的遍历:

for (k,v) in  dict.items():
    print ("dict[%s] ="% k,v)

值也可以是字典 元组 或者是字典,这种称为混合型字典。
字典有这么些方法:

keys() 返回keys列表
value()返回value列表
get()
get()访问字典中的value值减少了代码的长度,而且表达方式容易理解,避免了使用if语句带来的维护代价。
update()
update()函数相当于一个合并函数,把一个字典的key和value值全部复制到另外一个字典中。
D.update(E) -> None

把字典E的内容合并到字典D中,有相同的键值,e的值会覆盖d的。
setdefault()
可以创建新的元素并设置默认值,声明如下:

D.setdefault(k,[d]) -> D.get(k,[d])

还有一些常用方法:
items() 返回(key,value)元组组成的列表
iteritems() 返回指向字典的遍历器

字典还有排序和复制

排序的话和列表的差不多

print (sorted(dict.items(), key=lambda d:d[0]))

这是按照key排序

前面提到的update函数,比如把a字典的内容复制到b字典,并且b字典原有的顺序保持不变,从而实现字典b的扩展。但是,如果需要把a的内容复制到b,并且清除b中的原有内容的话,则需要使用copy()。

copy()是浅拷贝
还有deepcopy()是深拷贝

深拷贝能够拷贝对象内部所有的数据和引用,很像c语言中的指针。
字典b浅拷贝a的数据,如何b的数据发生添加 删除或者修改,a中的数据也将发生变化。
如果是深拷贝,a的数据是不会受到b的变化而变化的。

深拷贝和浅拷贝适用于python的任何对象,不只是局限于字典。

另外,还有全局字典 sys.modules模块,这个字典是python启动时就加载在内存当中的,这个起到缓存的作用。

##序列

序列是具有索引和切片能力的集合,元组 列表 字符串都属于序列。

这里主要是元组和列表的区别。

元组是只读的,而且元组没有提供排序和查找的方法。
列表可读写,而且提供丰富的操作,支持排序 查找。
元组的数据通常具有不同的含义,而列表的数据通常具有相同的含义。
相同之处则是都支持负数索引和分片的操作。

每天能适当做一些自己的总结,对于知识的掌握还是很有好处的。
希望自己能够好好坚持。
有目标的人咋个说呢?
今天看到一个前辈说,真正的牛人也许一辈子只投4次简历。
你就错过了毕业就去好公司的机会,所以需要更加努力学习。
对于初级的程序员来说,很想做出一点东西来,但是又不知道哪些重要哪些不重要,到底该学到什么程度,不知道导致不确定,不确定导致决策瘫痪,干脆就啥也不动,整年整年苦闷的像没头苍蝇一样到处乱撞,荒废时间。

今年不论在哪里工作,决定給自己设定一个目标,在博客上写下52篇博客,虽然前期可能借鉴他人的经验较多,但是希望自己还是能保持到平均一周一篇的水平,不断写写写去积累。

周博客这里可能局限于一些技术见闻,所见所感这块,另外希望自己能写下10篇左右的读书笔记。


没有什么面试比持续两年的面试更具有信息量,书单加上github。

macdown语法简介

发表于 2016-05-15 | 阅读次数:
字数统计: 451 | 阅读时长 ≈ 1

#markdown语法简介

1.标题
1)使用=和-标记一级和二级标题
使用方法是文字下方加上======这样

一级标题

2) 使用#,可以表示1-6级标题

##二级标题

2.段落
段落的前后要有空行,所谓的空行是指没有文字内容。
若想在段内强制换行的方式是使用两个以上空格加上回车(引用中换行省略回车)。

3.区块引用
在段落的每行或者只在第一行使用符号>,还可以使用多个嵌套引用,如:

区块引用

嵌套引用

4.代码区块
代码区块的建立是在每行加上4个空格或者一个制表符(如同写代码一样)。如
普通段落:

void main()
{
printf("Hello, Markdown.");
}

注意:需要和普通段落之间存在空行。

5.强调
在强调内容两侧分别加上或者_,如: , 还是斜体

粗体, 还是粗体

6.列表
使用*、+、或-标记无序列表,如:

  • 为什么
  • 怎么办
  • 啥时候

有序列表的标记方式是将上述的符号换成数字,并且加上点

  1. 第一点

7.分割线

分割线最常使用就是三个或以上*,还可以使用_。

大道至简


道法三千


杏杏冥冥

8.链接
链接可以由两种形式生成:行内式和参考式。

行内式:
markdown库

参考式:
younghz的Markdown库1
younghz的Markdown库2

9.图片

添加图片的形式和链接相似,只需在链接的基础上前方加一个!。
10.反斜杠\

相当于反转义作用。使符号成为普通符号。

11.符号``

起到表记作用。如:

ctrl+a

12.表格

Tables Are Cool
col 3 is right-aligned $1600
col 2 is centered $12
zebra stripes are neat $1

爬虫实践教程3-多进程

发表于 2016-05-15 | 分类于 pachong | 阅读次数:
字数统计: 402 | 阅读时长 ≈ 1

python爬虫多数都是运行在linux内核的服务器上的,多进程比多线程更合适,调度开销差不多,但是进程性能更好。
爬虫不是服务器交互,一般情况下提升几倍效率即可。

直接来看看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#coding:utf-8
import multiprocessing
from bs4 import BeautifulSoup
import requests

#url详情页
def pageUrls(url):
web_data = requests.get(url)
soup = BeautifulSoup(web_data.text, 'lxml')
sum = int(soup.select('span.total > em:nth-of-type(1)')[0].get_text())
pageNum = sum/50
return [url+'/loupan/s?p={}'.format(str(i)) for i in range(1, pageNum+2, 1)]

def detailPage(myurl):
urls = pageUrls(myurl)
for url in urls:
web_data = requests.get(url)
soup = BeautifulSoup(web_data.text, 'lxml')
titles = soup.select('div.list-results > div.key-list > div > div.infos > div > h3 > a')
for title in titles:
print url
print title.get_text()
print title.get('href')
print "**********"

def main(urls):
pool = multiprocessing.Pool(multiprocessing.cpu_count())
for url in urls:
pool.apply_async(detailPage, (url, ))
# pool.map(detailPage, urls)
pool.close()
pool.join()


if __name__ == "__main__":
startUrl = 'http://gz.fang.anjuke.com/?from=navigation'
web_data = requests.get(startUrl)
soup = BeautifulSoup(web_data.text, 'lxml')
urls = [url.get('href') for url in soup.select('.city-mod > dl > dd > a')]
main(urls)

这次我们准备爬取的是安居客的网站。
先从主代码开始,startUrl,使用requests和beautifulsoup进行解析。获取地址之后,进入main函数。
multiprocessing 创建一个进程池,进程个数为cpu内核数,一般写4或6个即可。
apply_async函数从进程池中取出一个进程执行func,args为func的参数,我们这段代码不断地从进程池中取出进程去执行我们的detailPage方法。当然,也可以采用下面这种方式:

pool.map(detailPage, urls)

接着就是关闭进程池还有wait进程池中的全部进程。

爬虫实践教程2

发表于 2016-05-15 | 分类于 pachong | 阅读次数:
字数统计: 781 | 阅读时长 ≈ 3

这里先介绍一下,我们使用工具selenium和Phantomjs来配合抓取。
安装的话, 直接

pip install -U selenium

而Phantomjs则通过brew来安装,不细说。

brew install phantomjs

选择原因:
Phantomjs是基于webkit的没有界面的浏览器,可以像浏览器一样解析网页,个人感觉的效果比firefox和chrome稍微快些。
selenium是web的自动测试工具,可以模拟人的操作。几乎支持市面上所有的主流浏览器。

来看看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#coding:utf-8
import unittest
from selenium import webdriver
from bs4 import BeautifulSoup


class seleniumTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.PhantomJS()

def testEle(self):
driver = self.driver
driver.get('http://www.douyu.com/directory/all')
soup = BeautifulSoup(driver.page_source, 'xml')
while True:
titles = soup.find_all('h3', {'class': 'ellipsis'})
nums = soup.find_all('span', {'class': 'dy-num fr'})
for title, num in zip(titles, nums):
print title.get_text(), num.get_text()
if driver.page_source.find('shark-pager-disable-next') != -1:
break
elem = driver.find_element_by_class_name('shark-pager-next')
elem.click()
soup = BeautifulSoup(driver.page_source, 'xml')

def tearDown(self):
print 'down'

if __name__ == "__main__":
unittest.main()

这里一些概念说明:
1.unittest 单元测试,简单的测试用例。以setup开头,中间测试的方法以test开头,测试完成之后会有一个teardown。
2.斗鱼tv是看直播时较常去的,直接用浏览器打开 斗鱼
网页源码中可以直接看到房间的信息,返回的不是json格式而是html,直接使用phantomjs模拟浏览器的访问过程,通过driver.get方法获取浏览器加载完成后的代码,无论是否是异步,取到的source都是和在浏览器中看到的完全一样!

这里lxml方式有数据丢失,原因未知。。后来尝试了xml无误,暂时不知原因。。

还有对比之前的瓜子和果壳,我们只从中抓取了部分页面。这里抓取全部我们需要加上条件判断,最后一页时斗鱼下一页的标签会变灰,这个时候我们就加上这个跳出循环。

if driver.page_source.find('shark-pager-disable-next') != -1: 
    break  

还有这里

elem = driver.find_element_by_class_name('shark-pager-next') 
elem.click() 
soup = BeautifulSoup(driver.page_source, 'xml')

第一行代码是webdriver里面带有的定位标签的方法,直接使用class来定位,取到这个控件,
然后执行element的click()方法模拟鼠标的点击,
页面会自动跳到下一页,接着解析网页的源码。

tips
这里加上一点selenium的小操作
编码学习的一个小突破感觉就是不断滴回顾学习吧,有些看完文档之后,觉得是这样没错,可是不久就好像啥也不剩了,在基础阶段模范性学习当中,要不断深化下已经学到的东西,适当做些归纳总结会很好。

填入表单数据

#coding:utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get('https://www.baidu.com/')
elem = driver.find_element_by_id('kw')
elem.send_keys(u'爬虫')
elem.send_keys(Keys.RETURN)
print(driver.page_source)

滚动页面至最下方

#coding:utf-8
from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get('http://www.jianshu.com/collections')
time.sleep(1)
for i in range(10):
    dirver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(1)

爬虫实践教程1

发表于 2016-05-15 | 分类于 pachong | 阅读次数:
字数统计: 294 | 阅读时长 ≈ 1

一般来说呢,很多网页都是直接分好页面直接下一页这样。不过还有很多网页是ajax异步请求数据的网页,以果壳网为例,我们尝试一下抓取。

# coding:utf-8
from bs4 import BeautifulSoup
import requests
import json
import pymongo

url = 'http://www.guokr.com/scientific/'

def dealData(url):
    client = pymongo.MongoClient('localhost', 27017)
    guoke = client['guoke']
    guokeData = guoke['guokeData']
    web_data = requests.get(url)
    datas = json.loads(web_data.text)
    print datas.keys()
    for data in datas['result']:
        guokeData.insert_one(data)

def start():
    urls = ['http://www.guokr.com/apis/minisite/article.json?retrieve_type=by_subject&limit=20&offset={}&_=1462252453410'.format(str(i)) for i in range(20, 100, 20)]
    for url in urls:
        dealData(url)

start()
'''
异步加载的网站  这里比如果壳网的抓取
'''

网页的抓取大概流程就是这样:
1.使用谷歌或者火狐浏览器,检查元素,分析下我们想抓取什么,有啥子障碍。
2.异步加载的数据不在返回的网页源码中,在网络标签和xhr分页面,向下滑动鼠标可以发现新的get请求被列出来。偏移量是多少,需要好好总结规律,然后不断尝试。

1…107108109
John Cheung

John Cheung

improve your python skills

543 日志
33 分类
45 标签
RSS
GitHub Email
© 2020 John Cheung
本站访客数:
|
主题 — NexT.Pisces v5.1.4
博客全站共226.3k字