django中的Q()函数:应用于model数据查询的与(and)或(or)操作

问题背景

之前用django的时候,数据库这一块也没有涉及到比较复杂一点的查询,一般就是一个filter()或者一个get()就搞定了,前几天做一个可视化的项目时,遇到了多条件复合查询,看了下文档,django的orm还是挺好用的,Q()函数可以解决这个问题。

比如我要查询id为1或者id为2的一个数据,在filter里面,是不能够这么直接来的:filter(id=1,id=2),只能使用Q函数。为了更深入地理解Q函数,我参考官方文档,整理一下它的用法。

文档位置:https://docs.djangoproject.com/en/1.9/topics/db/queries/#complex-lookups-with-q-objects

django中Q()函数的介绍

如果你需要进行复杂的查询(比如or条件),你可以使用Q对象。

Q对象是用来封装查询参数的,比如,它可以仅仅用来封装单独一个like查询:

from django.db.models import Q
Q(question__startswith='What')

Q函数可以通过逻辑符号连接

Q对象可以和&|这两个符号一起来使用,即and和or。下面这个例子就用or将两个查询组合在了一起:

Q(question__startswith='Who') | Q(question__startswith='What')

相当于以下sql语句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

另外,还可以使用非符号~,比如:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Q函数用于数据库查询

以上介绍了Q的组合方法,那么怎么把它应用到数据库的查询呢?一般而言,可以把它们放到filter(),get()或者exclude()里面,比如:

Poll.objects().filter(Q(question__startswith='Who') | ~Q(pub_date__year=2005))

Q函数和关键字参数混合使用

另外,Q对象还可以和关键字参数一起使用,不过Q一定要放在前面,以下是正确例子:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

相当于sql查询语句如下:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

关键字参数放在前面是错误的用法!!如下是错误的!

# 错误用法
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

我的实践

我喜欢这样来用Q对象。先在外面将条件组合好,然后再传入filter()get()或者exclude()里面,代码片段如下:

from django.db.models import Q
my_filter = Q()
my_filter = my_filter | Q(id=1)
my_filter = my_filter | Q(name="lipengfei")
result = People.objects.filter(my_filter)

java获取网页正文:WebCollector

WebCollector是一个无须配置、便于二次开发的JAVA爬虫框架(内核),它提供精简的的API,只需少量代码即可实现一个功能强大的爬虫。

Github上面更新到最新版本2.28,maven的中央仓库暂时只更新到2.09

2.09版本似乎没有把ContentExtractor集成进来,所以还是建议直接在github上先下载最新版本的jar,然后在buildpath里面引进来就行。

项目介绍:http://crawlscript.github.io/WebCollector/

项目github:https://github.com/CrawlScript/WebCollector

中文文档:https://github.com/CrawlScript/WebCollector/blob/master/README.zh-cn.md

来个简单的例子,对于中文url的支持,这个框架还是可以的。

import cn.edu.hfut.dmic.contentextractor.ContentExtractor;
import cn.edu.hfut.dmic.contentextractor.News;

public class WebExtraction {
    public static void main (String args[]) throws Exception{
        String url = "https://www.lookfor404.com/利用bootstrap的滚动监听+affix做一个侧导航landingpage/";
	String content = ContentExtractor.getContentByUrl(url);
	System.out.println("content:"+content);
	News news = ContentExtractor.getNewsByUrl(url);
	System.out.println("title:"+news.getTitle());
	System.out.println("content:"+news.getContent());
	}
}

输出结果如下:
webcollector例子输出结果

python获取网页正文:goose-extractor

做项目要用到提取网页的正文内容,于是在网上找找有什么好用的库。先测试一下,发现python就有现成的库,叫做goose-extractor。

事不宜迟,开始安装吧。

pip install goose-extractor

什么?出现问题了。

在安装依赖的lxml的时候,出现了以下的错误提示:

Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin\\amd64\\cl.exe’ failedwith exitstatus 2

找不到好的解决方案,最后祭出大杀器。直接用编译好的。

先打开http://www.lfd.uci.edu/~gohlke/pythonlibs/

ctrl+F搜索lxml,然后下载它对应的whl文件,下载之后pip install xxx.whl即可安装!

安装完这个比较难缠的lxml之后,就方便了,重新pip install goose-extractor

等待安装成功。

使用非常简单,给出一个实例代码,抓取《https://www.lookfor404.com/简易python爬虫–爬取冷笑话/》的正文内容。

# -*- coding: utf-8 -*-
from goose import Goose
from goose.text import StopWordsChinese
url  = 'https://www.lookfor404.com/%e7%ae%80%e6%98%93python%e7%88%ac%e8%99%ab-%e7%88%ac%e5%8f%96%e5%86%b7%e7%ac%91%e8%af%9d/'
g = Goose({'stopwords_class': StopWordsChinese})
article = g.extract(url=url)
print article.cleaned_text

效果不错,截取一下控制台的输出:
goose-extractor提取网页正文结果

但是速度并不快,具体里面怎么实现的还没看,但是它要用到python的结巴分词,估计这个耗时久一点,另外还有一个问题,就是我<code>标签里面的内容,被过滤掉了,所以抓取技术文章,有点不合适,哈哈。

Mysql在linux下的使用以及用java编程

平时管理mysql喜欢用可视化的phpmyadmin,方便易用,简单的事情就不要复杂化。今天在做项目的过程中,发现需要远程连接mysql数据库,虽然说phpmyadmin是可以连接远程的数据库的,但是需要远程的数据库对我这边开启一定的访问权限。

鉴于安全考虑,打消了这个念头。

而想想,自己无非就是想去看看表的结构,select几个字段罢了,那就直接登录直接使用吧,遂把今天的一些操作记录一下吧。

linux下使用mysql

安装就不说了,直接进入主题。

先登录,命令如下:其中,-u后面直接输入用户名,-p后面直接输入密码

mysql -uusername -ppassword

无意外,登录成功。

在这里记录一个坑,那就是登录成功之后,进入mysql的命令行模式,此后输入命令都要以分号;结尾,就和我们日常编程一样,否则输入命令之后,会没有任何错误提示,并且也不会有任何反应。

首先看看有哪些数据库:

show databases;

选择一个数据库,比如我想对数据库名为test的数据库进行操作。

use test;

之后,就是输入各种select语句就行了。最后退出的时候输入命令exit就行。

Java下mysql的使用

首先下载mysql的jdbc驱动,去搜索mysql-connector-java,然后下载。

我搜索到的下载地址:http://dev.mysql.com/downloads/connector/j/

然后新建一个工程,把下载的jar包引进去就行。

随后开始编程,使用很简单,我写了一个简单的example记录一下,操作都大同小异,不过我这里用的不是存储过程,而是基本的sql语句操作。附上代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;




public class mysqlExample {
	public static void main(String args[]) {
		try {
			Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序
			System.out.println("加载驱动成功!");
		} catch (Exception e) {
			System.out.print("加载驱动失败!");
			e.printStackTrace();
		}




		try {
			Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName", "root", "");
			System.out.println("连接到数据库成功");
			String sql = "select * from `user`;";
			ResultSet rs = getResult(sql,connection);
			//遍历结果,rs是结果游标 
			while(rs.next()) { 
				 /*
				  * getString方法可以传int index,即第几列(1代表结果的第一列..)
				  * 也可以传String columnname,可以直接指定要哪个字段
				  */
				 System.out.println(rs.getString(1));
				 System.out.println(rs.getString("admin"));
				 } 
			 //关闭连接
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 获取sql查询结果
	 * @param sql sql语句
	 * @param connection 连接
	 * @return 结果集
	 * @throws SQLException
	 */
	public static ResultSet getResult(String sql,Connection connection) throws SQLException{
		Statement stmt = connection.createStatement();
		ResultSet rs = stmt.executeQuery(sql);
		return rs;
	}
}

记录一下maven使用过程中遇到的几个问题

环境:win7+eclipese-mars+maven3.3.9

卡死在building workspace

这个问题网上我找了好多,原因不一而足。有一种解决办法就是,先停止它的building,然后项目右键–properties,在左边选择builder,然后把Maven Project Builder的选项去掉就行。

builder

这个方法堪称是鸵鸟战法,只是让eclipse没再卡在building workspace的状态中了,之后该干什么还是得干什么。

我接下来就继续maven install了,把依赖包都下下来了,但是一看Maven Dependencies,什么都没有。。可到本地的repository看看,依赖包确实是下载了啊。

好吧,我又把Maven Project Builder的选项勾选回来了,然后打开pom.xml,随便打了一个空格,保存,依赖包神奇的包含进来了。

reload maven project出错,eclipse打不开

这个问题原因同样很多。我就是因为等不及maven卡在那里,eclipse又关不了,直接暴力在任务管理器中关掉eclipse了,然后发现eclipse再也打不开了,错误信息是

"An internal error occurred during: "reload maven project".java.lang.NullPointerException"

估计的某些文件没弄下来,然后被我直接关了,没保存好,就启动出错了。

简单粗暴的解决方法:到你eclipse的workspace目录下,把.metadata文件夹删掉,然后重启eclipse就可以正常打开了。

代价是:要重新导入原来的项目,但是项目本身还是在那里的,相比于看log来找错误信息,这个解决问题的方式虽然比较粗暴,但胜在速度比较快。

使用开源中国的maven中央仓库

国外的maven中央仓库相对来说还是比较慢的,好在国内的开源中国有做这方面的优化,他们将国外的仓库搬过来了,一天一更新,基本上也是同步的,速度快多了,推荐使用他们的mirror。

官方教程:http://maven.oschina.net/help.html

仓库搜索:http://maven.oschina.net/home.html

记录一下windows下panda的安装过程

搞大数据开发,就是和数据打交道,具体怎么处理数据,也需要深究,python有很多很好用的库,其中pandas是比较出名的。下面是简单的介绍:

Pandas是python的一个数据分析包,最初由AQR Capital Management于2008年4月开发,并于2009年底开源出来,目前由专注于Python数据包开发的PyData开发team继续开发和维护,属于PyData项目的一部分。Pandas最初被作为金融数据分析工具而开发出来,因此,pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了panel的数据类型。

官网:http://pandas.pydata.org/

我刚开始以为直接pip就能安装pandas了。事实证明我太天真了。下面还是记录一下我的安装过程吧。

利用pycharm直接安装pandas

pycharm的包管理工具挺好用的,直接可以在里面搜索到很多可以用的包,然后直接安装。安装pandas也不例外。

首先打开pycharm,直接在setting里面找到编译器的选项

pycharm中编译器设置

可以看到本地已经安装的包,点击右边的+号,就可以安装新的包了。想安装pandas,直接搜索pandas就是了,记得别少了s,是pandas

搜索后安装即可。pandas是依赖于别的包的,根据提示,如果还需要安装别的包,继续搜索安装就行。

在windows下用pip安装pandas

官网推荐的是直接使用Anoconda,它集成了pandas,可以直接使用。安装挺简单的,有windows下的安装包。

如果不想安装庞大的Anoconda,那就一步一步用pip来安装pandas。

如果直接pip install pandas,可能会出现一系列的问题,为了稳妥起见,我先把依赖包都一个个安装下来,最后再安装pandas,就没有问题了。

官网说pandas需要以下几个依赖:

setuptools
NumPy: 1.7.1 or higher
python-dateutil 1.5 or higher
pytz

一个个来。首先setuptools,这个和pip本身在新一点的python下是默认安装了的。我的python版本是2.7.11

然后pip install numpy

安装numpy

安装到一般,居然出错了。错误如下:

Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat

原因:windows下使用pip安装包的时候需要机器装有vs2008,VS2012都不行,如果不想装VS2008的话,可以安装一个Micorsoft Visual C++ Compiler for Python 2.7的包。
下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=44266

如果还是不行的话,就直接去官网找windows下的安装包。

官网:http://sourceforge.net/projects/numpy/files/

我找的1.9.2版本:http://sourceforge.net/projects/numpy/files/NumPy/1.9.2/

有windows下针对python2.7的安装包,文件名为numpy-1.9.2-win32-superpack-python2.7.exe

下载安装即可。

搞定了numpy,接下来安装python-dateutil,命令:pip install python-dateutil
很顺利。

然后安装pytz,命令:pip install pytz
也很顺利。

最后!直接安装pandas就行了,命令:pip install pandas

安装pandas

大功告成,真是折腾。

利用bootstrap的滚动监听+affix做一个侧导航landingpage

前段时间有个小的需求,要做一个带侧边导航的landingpage。这种页面直观点来说,就是类似百度百科一样,随着页面的滚动,在旁边的导航栏会跟踪你的页面,作为一个活动书签。如图,红框就是侧导航:

百度百科侧边导航

要是直接重新写的话,也是一件有工作量的事情,所以干脆直接用bootstrap框架,里面js插件有滚动监听和affix,结合起来就可以做出来类似的效果。

ps:用的是bootstrap3

滚动监听

bootstrap的scroll.js是用来滚动监听的,而使用起来最便利的方法是直接引用在html代码里加data属性。

滚动监听都需要被监听的组件是position: relative; 即相对定位方式。大多数时候是监听 元素,所以直接在body的style里面加上这个属性即可。

然后继续在body里面加data属性,一个是data-spy,一个是data-target
data-spy的值直接设置成"scroll"即可,而data-target则要设置成导航栏的id。实例代码如下:

<body style="position: relative;" data-spy="scroll" data-target="#navbar-example">
  ...



<div id="navbar-example">



<ul class="nav nav-tabs" role="tablist">
      ...
    </ul>



  </div>



  ...
</body>

affix固定侧导航

affix的英文意思粘贴的意思,顾名思义,它的作用就是是网页中的元素固定粘贴在某个位置,而我们的侧边栏恰好就是要这样的效果。

使用方法也很简单,在侧导航加一个data-spy="affix"属性就可以了,可选项为data-offset,可以是data-offset-top或者data-offset-bottom,比如data-offset-top="60",效果就是当页面距离顶部60像素之后,才开始固定这个元素(侧导航),如果不用这个可选项,则侧导航是一直黏在固定位置的。

侧导航landingpage例子

效果是这样的:https://www.lookfor404.com/langding-page-example.html

全程都是用的data属性,其中,affix的属性,我没有加上data-offset,另外就是对“返回顶端”写了几行jquery,返回顶端的时候有滚动效果,代码如下:

<script type="text/javascript">
    $(function(){  
            $("#back-to-top").click(function(){  
                $('body,html').animate({scrollTop:0},1000);  
                return false;  
            });  
      });
    </script> 

完整代码直接在网页右键–查看源代码就行了,这里就不贴出来了。

python爬虫–抓取ajax更新的内容

虽然很多情况下,直接对一个url发出请求,就能得到页面的源代码,但是我们还得考虑这么一种情况,就是有的网站为了用户体验,采用了ajax技术–即不刷新页面而改变页面内容,那么我们该怎么获取这些内容呢?

从本质出发,ajax技术也就是这么一个过程:利用js来发起一个post请求–然后接收返回的数据–js改变页面内容。在大多数情况下,我们都是点击一个按钮,然后页面就更新了。从原理上来看,点击某个按钮,就会发送一个post请求(当然还有滚动鼠标发送请求的),服务器再返回结果,再将结果直接更新到页面上。我们的思路是–用爬虫发送同样的post请求,从而获得返回来的数据。

简单点说,对于爬虫而言,在获取数据上,get和post并无太多异样,只是get的话,我们只需要对某个链接发送请求就行,而post,则需要一些表单内容。那么,我们怎么知道该post什么内容过去,又能获得什么响应呢?

以虎嗅网(http://www.huxiu.com/)为例,我用python写了一个爬取它利用ajax更新的数据。

我们打开它的首页,拉到最下面,发现有个“点击加载更多”的按钮,颜色很浅。

点击它,就会有新的内容出现。

虎嗅网底部

我们要做的,就是看看点击这个按钮会发生什么。

我这里以遨游浏览器为例,大多数浏览器(比如chrome,Firefox)应该都有类似的功能,在网页上,点击右键–审查元素,在弹出的窗口菜单栏点击“网络”一栏,在这里,我们可以监控一些get,post等行为。

刚开始是空的。

此时,回到网页上去,点击“点击加载更多”按钮。然后再回到开发者工具那里,会发现,出现了很多的请求:

点击加载更多

其中,有个请求的方法是POST,这就是我们要找的。点进去,可以看到http报头、预览、响应和cookies。

从中,我们可以获得一些头部信息,以及post的表单数据。

  • 头部信息

不同网站对头部信息的要求不同,有的不需要头部信息都能响应,有的则需要头部信息的一部分,虎嗅是不需要头部信息的。

  • 表单数据

从开发者工具里面看,虎嗅需要的表单数据有两个,一个是’huxiu_hash_code‘,这个是用来防止csrf的,一个是page,代表页数,我们把huxiu_hash_code复制下来。

构造一个请求过去,会得到一个json格式的响应,内容有msg,total_page,result和data,要的文章数据在data里面。我的程序把data里面的标题都提取出来,打印到屏幕下,下面贴上代码:

#-*- coding:utf-8 -*-
__author__ = '李鹏飞'
import urllib2
import urllib
import json
import re
url = 'http://www.huxiu.com/v2_action/article_list'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
data = {'huxiu_hash_code':'322cf76eec54c4e275d7c8122028a3b2','page':2}
data = urllib.urlencode(data)
try:
    request = urllib2.Request(url=url,data=data)
    response = urllib2.urlopen(request)
    #解析json
    result = json.loads(response.read())
    print result['msg']
    content = result['data']
    #匹配文章标题
    pattern = re.compile('
<div class="mob-ctt">.*?target="_blank">(.*?)</a>',re.S)
    #虎嗅文章标题
    items = re.findall(pattern,content)
    for item in items:
        print item
except urllib2.URLError, e:
    if hasattr(e,"code"):
        print e.code
    if hasattr(e,"reason"):
        print e.reason

这样子的话,大部分网页就能抓了,管他是post还是get。

Linux下升级python版本-2.7.9

我用的centos,预装着python,版本比较低,是2.6的,而2.7.9以上的版本自带pip,easy_instll和wheel,为了省去安装这些东西的麻烦,我干脆直接重新装一个python2.7.9好了。

这里记录一下升级安装的过程。

首先去官网下载对应的python的tgz文件,在linux下可以直接wget,在windows下直接下载就行,网址:https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz

若网址失效,请移步python官网下载。

在linux下,将下载的tgz文件解压到指定目录,运行以下命令:

tar -xvzf Python-2.7.9.tgz -C /home 

解压完成,切换到解压的目录下,运行命令:

./configure

这个命令完成后,会生成makefile文件,供下一步使用。

接下来编译源代码,运行命令:

make

再运行最后一个命令,自动把文件分发的系统的关键位置,命令如下:

make install

等到处理完成,不需要任何更改,直接在命令行输入python,看到如下提示即安装成功:
python升级成功

2.7.9以及以上版本的python都预装了pip,eazy_install,很是方便,之后安装别的包就比较简单了。

cloudera-quickstart-vm-集成了大数据平台的虚拟机镜像

前几天和朋友聊天,他告诉我有一个cloudera-quickstart,这是一个集成了大部分大数据组件的虚拟机镜像系统,反正就是–不用配置了,包括hadoop,hbase,hive,hue,spark,zookeeper等等,是cloudera定制的版本,还有cloudera的管理组件。我们只需要把镜像下下来,直接在visualbox或者vmvare里面运行就行。

于是我就自己尝试了一下vmvare的版本,不过出了问题,主要是内存不足。在这里也提醒一下想用quickstart-vm的朋友,你得保证你的电脑至少有8g的内存,配置越高越好,不然会很卡。

下面记录一下自己运行cloudera-quickstart-vm的vmvare版本

下载地址:http://www.cloudera.com/downloads.html

第一个就是quickstart-vm:

quickstart-vm下载

点击download下载。我下载的是vmvare的版本。PS:下载的时候可能会要求你登陆账号,注册一个就好。我得到的下载链接是:https://downloads.cloudera.com/demo_vm/vmware/cloudera-quickstart-vm-5.5.0-0-vmware.zip

整个zip大小4g多,本地用迅雷下载速度也快不到哪里去,于是我用百度网盘离线下载,秒下,然后再从百度云下到本地。

下载完成,解压。

打开vmvare,点击菜单栏上的文件–打开,找到刚才解压的路径,就能发现有一个vmx文件,打开它。

quickstart-vm虚拟机文件

打开之后,vmvare是这样的:

打开vmx文件的vmvare

先别急着运行,要先更改虚拟机的配置,你需要把这台虚拟机设置到至少8g内存(这意味着你的电脑需要至少需要8g内存,没有的话,会非常非常卡,而且一堆错误),处理器设置成至少两个。

vmvare内存和处理器的设置

这时候,可以启动这台虚拟机了。启动之后,它会自动启动火狐浏览器,打开一个初始页面:

quickstart初始界面

怎么进入管理界面呢?

运行桌面的cloudera express命令脚本即可。

如果出现以下错误,说明你的虚拟机没有设置到8g内存和两个处理器,请设置完毕再重新打开这个虚拟机。

quickstart错误

想强制启动的话,可以在终端运行以下命令:

sudo /home/cloudera/cloudera-manager --express --force

不出意外的话,启动成功了:

cloudera-quickstart管理组件启动成功

接下来可以去浏览器直接管理了。

打开内置的火狐,输入网址:http://quickstart.cloudera:7180

登录账号:cloudera
登录密码:cloudera

登陆之后,就可以看到管理界面了:

cloudera管理界面

可以看到,左边是整合的大数据工具,点击对应的下拉按钮,就可以启动,关闭,管理这些组件了。

PS:由于电脑内存太小,所以这个整合了所有单机版大数据工具的系统,我用的并不顺手,这里仅把过程记录下来,供大家参考。

PPS:还是乖乖搭环境去了