Python爬虫结合dedecms自动采集发布

之前想实现一个爬虫,实时采集别人的文章,根据自己的规则去修改采集到的文章,然后自动发布。决定用dedecms做新闻发布,还可以自动生成html,自动把远程图片本地化等一些优点,为了安全,完全可以把前后台分离。
起初想用scrapy爬虫框架去实现,觉得定制开发的话用scrapy只能用到里面的一些基础的功能,有一些情况要跟着框架的规则走,如果自己写的话可以自己写规则去处理,也有优点爬虫、处理器等,最后还是自己写了一个demo。
首先分析需求,python做爬虫,dedecms做发布,起初先考虑了发布功能,实现了模拟登陆,或者研究dedecms的数据库设计,直接写到数据库,实际中没有这样去做,开始做模拟登陆的时候,需要改dedecms的代码去掉验证码,不然还要实现验证码识别,这个完全没有必要,因为要发布的是自己的网站,自己也有账户、密码、发布文章权限,然后就改了下dedecms的登陆功能,加了一个登陆接口,分析了dedecms的发布文章HTTP数据包。这块搞定了后就开始设计爬虫了,最后设计的感觉和scrapy的一些基础的处理机制很像。

做dedecms的登陆接口如下:
后台目录下的config.php 34行找到

/**
//检验用户登录状态
$cuserLogin = new userLogin();
if($cuserLogin->getUserID()==-1)
{
header(“location:login.php?gotopage=”.urlencode($dedeNowurl));
exit();
}
**/

改为下面
//http://127.0.0.2/dede/index.php?username=admin&password=admin

$cuserLogin = new userLogin();
if($cuserLogin->getUserID()==-1) {
if($_REQUEST['username'] != ''){
$res = $cuserLogin->checkUser($_REQUEST['username'], $_REQUEST['password']);
if($res==1) $cuserLogin->keepUser();
}

if($cuserLogin->getUserID()==-1) {
header("location:login.php?gotopage=".urlencode($dedeNowurl));
exit();
}
}

这样只要请求:http://127.0.0.2/dede/index.php?username=admin&password=admin 就可以得到一个sessionid,只要用这个sessionid去发布文章就可以了。

发布文章的HTTP数据包如下:
#http://127.0.0.2/dede/article_add.php
POST /dede/article_add.php HTTP/1.1
Host: 127.0.0.2
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.2/dede/article_add.php?cid=2
Cookie: menuitems=1_1%2C2_1%2C3_1; CNZZDATA1254901833=1497342033-1472891946-%7C1473171059; Hm_lvt_a6454d60bf94f1e40b22b89e9f2986ba=1472892122; ENV_GOBACK_URL=%2Fmd5%2Fcontent_list.php%3Farcrank%3D-1%26cid%3D11; lastCid=11; lastCid__ckMd5=2f82387a2b251324; DedeUserID=1; DedeUserID__ckMd5=74be9ff370c4536f; DedeLoginTime=1473174404; DedeLoginTime__ckMd5=b8edc1b5318a3923; hasshown=1; Hm_lpvt_a6454d60bf94f1e40b22b89e9f2986ba=1473173893; PHPSESSID=m2o3k882tln0ttdi964v5aorn6
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=—————————2802133914041
Content-Length: 3639
—————————–2802133914041
Content-Disposition: form-data; name=”channelid”

1
—————————–2802133914041
Content-Disposition: form-data; name=”dopost”

save
—————————–2802133914041
Content-Disposition: form-data; name=”title”

2222222222
—————————–2802133914041
Content-Disposition: form-data; name=”shorttitle”

—————————–2802133914041
Content-Disposition: form-data; name=”redirecturl”

—————————–2802133914041
Content-Disposition: form-data; name=”tags”

—————————–2802133914041
Content-Disposition: form-data; name=”weight”

100
—————————–2802133914041
Content-Disposition: form-data; name=”picname”

—————————–2802133914041
Content-Disposition: form-data; name=”litpic”; filename=””
Content-Type: application/octet-stream

—————————–2802133914041
Content-Disposition: form-data; name=”source”

—————————–2802133914041
Content-Disposition: form-data; name=”writer”

—————————–2802133914041
Content-Disposition: form-data; name=”typeid”

2
—————————–2802133914041
Content-Disposition: form-data; name=”typeid2″

—————————–2802133914041
Content-Disposition: form-data; name=”keywords”

—————————–2802133914041
Content-Disposition: form-data; name=”autokey”

1
—————————–2802133914041
Content-Disposition: form-data; name=”description”

—————————–2802133914041
Content-Disposition: form-data; name=”dede_addonfields”

—————————–2802133914041
Content-Disposition: form-data; name=”remote”

1
—————————–2802133914041
Content-Disposition: form-data; name=”autolitpic”

1
—————————–2802133914041
Content-Disposition: form-data; name=”needwatermark”

1
—————————–2802133914041
Content-Disposition: form-data; name=”sptype”

hand
—————————–2802133914041
Content-Disposition: form-data; name=”spsize”

5
—————————–2802133914041
Content-Disposition: form-data; name=”body”

2222222222
—————————–2802133914041
Content-Disposition: form-data; name=”voteid”

—————————–2802133914041
Content-Disposition: form-data; name=”notpost”

0
—————————–2802133914041
Content-Disposition: form-data; name=”click”

70
—————————–2802133914041
Content-Disposition: form-data; name=”sortup”

0
—————————–2802133914041
Content-Disposition: form-data; name=”color”

—————————–2802133914041
Content-Disposition: form-data; name=”arcrank”

0
—————————–2802133914041
Content-Disposition: form-data; name=”money”

0
—————————–2802133914041
Content-Disposition: form-data; name=”pubdate”

2016-09-06 23:07:52
—————————–2802133914041
Content-Disposition: form-data; name=”ishtml”

1
—————————–2802133914041
Content-Disposition: form-data; name=”filename”

—————————–2802133914041
Content-Disposition: form-data; name=”templet”

—————————–2802133914041
Content-Disposition: form-data; name=”imageField.x”

41
—————————–2802133914041
Content-Disposition: form-data; name=”imageField.y”

6
—————————–2802133914041–
#更新生成html请求
http://127.0.0.2/dede/task_do.php?typeid=2&aid=109&dopost=makeprenext&nextdo=

GET /dede/task_do.php?typeid=2&aid=109&dopost=makeprenext&nextdo= HTTP/1.1
Host: 127.0.0.2
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.2/dede/article_add.php
Cookie: menuitems=1_1%2C2_1%2C3_1; CNZZDATA1254901833=1497342033-1472891946-%7C1473171059; Hm_lvt_a6454d60bf94f1e40b22b89e9f2986ba=1472892122; ENV_GOBACK_URL=%2Fmd5%2Fcontent_list.php%3Farcrank%3D-1%26cid%3D11; lastCid=11; lastCid__ckMd5=2f82387a2b251324; DedeUserID=1; DedeUserID__ckMd5=74be9ff370c4536f; DedeLoginTime=1473174404; DedeLoginTime__ckMd5=b8edc1b5318a3923; hasshown=1; Hm_lpvt_a6454d60bf94f1e40b22b89e9f2986ba=1473173893; PHPSESSID=m2o3k882tln0ttdi964v5aorn6
Connection: keep-alive
Upgrade-Insecure-Requests: 1

通过上面数据包可以分析到如下结果:
POST http://127.0.0.2/dede/article_add.php
需要配置的参数:

channelid:1 #普通文章提交
dopost:save #提交方式

shorttitle:” #短标题
autokey:1 #自动获取关键词
remote:1 #不指定缩略图,远程自动获取缩略图
autolitpic:1 #提取第一个图片为缩略图
sptype:auto #自动分页
spsize:5 #5k大小自动分页
notpost:1 #禁止评论
sortup:0 #文章排序、默认
arcrank:0 #阅读权限为开放浏览
money: #消费金币0
ishtml:1 #生成html

title:”文章标题” #文章标题
source:”文章来源” #文章来源
writer:”文章作者” #文章作者
typeid:”主栏目ID2″ #主栏目ID
body:”文章内容” #文章内容
click:”文章点击量” #文章点击量
pubdate:”提交时间” #提交时间

然后开始模拟dedecms发布文章测试了,python代码如下:

#!/usr/bin/python
#coding:utf8
import requests,random,time

#访问登陆接口保持cookies
sid = requests.session()
login_url = "http://127.0.0.2/dede/index.php?username=admin&password=admin"
header = {    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
"Referer"    :"http://127.0.0.2"
}

#登陆接口获取Cookies
loadcookies = sid.get(url = login_url,headers = header)

#进入增加文章页面
#get_html = sid.get('http://127.0.0.2/dede/article_add.php?channelid=1',headers = header)
#print get_html.content

#定义固定字段
article = {
'channelid':1, #普通文章提交
'dopost':'save', #提交方式
'shorttitle':'', #短标题
'autokey':1, #自动获取关键词
'remote':1, #不指定缩略图,远程自动获取缩略图
'autolitpic':1, #提取第一个图片为缩略图
'sptype':'auto', #自动分页
'spsize':5, #5k大小自动分页
'notpost':1, #禁止评论
'sortup':0, #文章排序、默认
'arcrank':0, #阅读权限为开放浏览
'money': 0,#消费金币0
'ishtml':1, #生成html
'click':random.randint(10, 300), #随机生成文章点击量
'pubdate':time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), #s生成当前提交时间
}

#定义可变字段
article['source'] = "文章来源" #文章来源
article['writer'] = "文章作者" #文章作者
article['typeid'] = "2" #主栏目ID

#定义提交文章请求URL
article_request = "http://127.0.0.2/dede/article_add.php"

"""
#测试提交数据
article['title'] = "测试_文章标题" #文章标题
article['body'] = "测试_文章内容" #文章内容
#提交后会自动重定向 生成html,http返回状态为200则成功!
res = sid.post(url = article_request,data = article, headers = header)
print res
"""
for i in range(50):
    article['title'] = str(i) + "_文章标题" #文章标题
    article['body'] = str(i) + "_文章内容" #文章内容
    #print article
    res = sid.post(url = article_request,data = article, headers = header)
    print res

其次就是分析爬虫需求阶段了,如下:

收集采集页面:

http://www.tunvan.com/col.jsp?id=115
http://www.zhongkerd.com/news.html
http://www.qianxx.com/news/field/
http://www.ifenguo.com/news/xingyexinwen/
http://www.ifenguo.com/news/gongsixinwen/

每一个采集页面和要改的规则都不一样,发布文章的栏目可能也有变化,要写多个爬虫,一个爬虫实现不了这个功能,要有爬虫、处理器、配置文件、函数文件(避免重复写代码)、数据库文件。

数据库里面主要是保存文章url和标题,主要是判断这篇文章是否是更新的,如果已经采集发布了就不要重复发布了,如果不存在文章就是最新的文章,需要写入数据库并发布文章。数据库就一个表几个字段就好,采用的sqlite3,数据库文件db.dll建表如下:

CREATE TABLE history (
id    INTEGER         PRIMARY KEY ASC AUTOINCREMENT,
url   VARCHAR( 100 ),
title TEXT,
date  DATETIME        DEFAULT ( ( datetime( 'now', 'localtime' )  )  )
);

架构设计如下:

│ db.dll #sqlite数据库
│ dede.py #测试dede登陆接口
│ function.py #公共函数
│ run.py #爬虫集开始函数
│ settings.py #爬虫配置设置
│ spiders.py #爬虫示例
│ sqlitestudio-2.1.5.exe #sqlite数据库编辑工具
│ __init__.py #前置方法供模块用

dede.py如下:

#!/usr/bin/python
#coding:utf8
import requests,random,time
import lxml

#定义域名
domain = "http://127.0.0.2/"
admin_dir = "dede/"
houtai = domain + admin_dir
username = "admin"
password = "admin"

#访问登陆接口保持cookies
sid = requests.session()
login_url = houtai + "index.php?username=" + username + "&password=" + password
header = {    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
"Referer"    : domain
}

#登陆接口获取Cookies
loadcookies = sid.get(url = login_url,headers = header)

#定义固定字段
article = {
'channelid':1, #普通文章提交
'dopost':'save', #提交方式
'shorttitle':'', #短标题
'autokey':1, #自动获取关键词
'remote':1, #不指定缩略图,远程自动获取缩略图
'autolitpic':1, #提取第一个图片为缩略图
'sptype':'auto', #自动分页
'spsize':5, #5k大小自动分页
'notpost':1, #禁止评论
'sortup':0, #文章排序、默认
'arcrank':0, #阅读权限为开放浏览
'money': 0,#消费金币0
'ishtml':1, #生成html
'click':random.randint(10, 300), #随机生成文章点击量
'pubdate':time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), #s生成当前提交时间
}

#定义可变字段
article['source'] = "文章来源" #文章来源
article['writer'] = "文章作者" #文章作者
article['typeid'] = "2" #主栏目ID

#定义提交文章请求URL
article_request = houtai + "article_add.php"

"""
#测试提交数据
article['title'] = "11测试_文章标题" #文章标题
article['body'] = "11测试_文章内容" #文章内容
#提交后会自动重定向 生成html,http返回状态为200则成功!
res = sid.post(url = article_request,data = article, headers = header)
print res
"""

"""
for i in range(50):
    article['title'] = str(i) + "_文章标题" #文章标题
    article['body'] = str(i) + "_文章内容" #文章内容
    #print article
    res = sid.post(url = article_request,data = article, headers = header)
    print res
"""

function.py如下:

# coding:utf-8
from settings import *

#检查数据库中是否存在文章,0为不存在,1为存在
def res_check(article):
    exec_select = "SELECT count(*) FROM history WHERE url = '%s' AND title = '%s' "
    res_check = cur.execute(exec_select % (article[0],article[1]))
    for res in res_check:
        result = res[0]
    return result

#写入数据库操作
def res_insert(article):
    exec_insert = "INSERT INTO history (url,title) VALUES ('%s','%s')"
    cur.execute(exec_insert % (article[0],article[1]))
    conn.commit()

#模拟登陆发布文章
def send_article(title,body,typeid = "2"):
    article['title'] = title #文章标题
    article['body'] = body #文章内容
    article['typeid'] = "2"
    #print article
    #提交后会自动重定向 生成html,http返回状态为200则成功!
    res = sid.post(url = article_request,data = article, headers = header)
    #print res
    if res.status_code == 200 :
        #print u"send mail!"
        send_mail(title = title,body = body)
        print u"success article send!"
    else:
        #发布文章失败处理
        pass

#发邮件通知send_mail(收件,标题,内容)
def send_mail(title,body):
    shoujian = "admin@0535code.com"
    # 设置服务器,用户名、密码以及邮箱的后缀
    mail_user = "610358898"
    mail_pass="你的邮箱密码"
    mail_postfix="qq.com"
    me=mail_user+"<"+mail_user+"@"+mail_postfix+">"
    msg = MIMEText(body, 'html', 'utf-8')
    msg['Subject'] = title
    #msg['to'] = shoujian
    try:
        mail = smtplib.SMTP()
        mail.connect("smtp.qq.com")#配置SMTP服务器
        mail.login(mail_user,mail_pass)
        mail.sendmail(me,shoujian, msg.as_string())
        mail.close()
        print u"send mail success!"
    except Exception, e:
        print str(e)
        print u"send mail exit!"

run.py如下:

# -*- coding: utf-8 -*-
import spiders
    #开始第一个爬虫
    spiders.start()

settings.py如下:

# coding:utf-8
import re,sys,os,requests,lxml,string,time,random,logging
from bs4 import BeautifulSoup
from lxml import etree
import smtplib
from email.mime.text import MIMEText
import sqlite3
import HTMLParser

#刷新系统
reload(sys)
sys.setdefaultencoding( "utf-8" )
#定义当前时间
#now = time.strftime( '%Y-%m-%d %X',time.localtime())

#设置头信息
headers={       "User-Agent":"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36",
"Accept":"*/*",
"Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding":"gzip, deflate",
"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
"Connection":"keep-alive",
"X-Requested-With":"XMLHttpRequest",
}
domain = u"<a href='http://010bjsoft.com'>北京软件外包</a>".decode("string_escape") #要替换的超链接
html_parser = HTMLParser.HTMLParser() #生成转义器

########################################################dede参数配置

#定义域名
domain = "http://127.0.0.2/"
admin_dir = "dede/"
houtai = domain + admin_dir
username = "admin"
password = "admin"

#访问登陆接口保持cookies
sid = requests.session()
login_url = houtai + "index.php?username=" + username + "&password=" + password
header = {    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
"Referer"    : domain
}

#登陆接口获取Cookies
loadcookies = sid.get(url = login_url,headers = header)

#定义固定字段
article = {
'channelid':1, #普通文章提交
'dopost':'save', #提交方式
'shorttitle':'', #短标题
'autokey':1, #自动获取关键词
'remote':1, #不指定缩略图,远程自动获取缩略图
'autolitpic':1, #提取第一个图片为缩略图
'sptype':'auto', #自动分页
'spsize':5, #5k大小自动分页
'notpost':1, #禁止评论
'sortup':0, #文章排序、默认
'arcrank':0, #阅读权限为开放浏览
'money': 0,#消费金币0
'ishtml':1, #生成html
'click':random.randint(10, 300), #随机生成文章点击量
'pubdate':time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), #s生成当前提交时间
}

#定义可变字段
article['source'] = "文章来源" #文章来源
article['writer'] = "文章作者" #文章作者

#定义提交文章请求URL
article_request = houtai + "article_add.php"

########################################################数据库配置

#建立数据库连接
conn = sqlite3.connect("db.dll")
#创建游标
cur = conn.cursor()

spiders.py如下:

# coding:utf-8
from settings import *
from function import *

#获取内容, 文章url,文章内容xpath表达式
def get_content( url = "http://www.zhongkerd.com/news/content-1389.html" , xpath_rule = "//html/body/div[3]/div/div[2]/div/div[2]/div/div[1]/div/div/dl/dd" ):
    html = requests.get(url,headers = headers).content
    tree = etree.HTML(html)
    res = tree .xpath(xpath_rule)[0]
    res_content = etree.tostring(res) #转为字符串
    res_content = html_parser.unescape(res_content) #转为html编码 输出
    res_content = res_content.replace('\t','').replace('\n','') #去除空格 .replace(' ',''),换行符,制表符
    return res_content
#获取结果,url列表
def get_article_list(url = "http://www.zhongkerd.com/news.html" ):
    body_html = requests.get(url,headers = headers).content
    #print body_html
    soup = BeautifulSoup(body_html,'lxml')
    page_div = soup.find_all(name = "a",href = re.compile("content"),class_="w-bloglist-entry-link")
    #print page_div
    list_url = []
    for a in page_div:
        #print a
        #print a.get('href')
        #print a.string
        list_url.append((a.get('href'),a.string))
        #print get_content(a.get('href'))
    else:
        #print list_url
        return list_url
#处理采集页面
def res_content(url):
    content = get_content(url)
    #print content
    info = re.findall(r'<dd>(.*?)</dd>',content,re.S)[0] #去掉dd标签

    re_zhushi = re.compile(r'<!--[^>]*-->') #HTML注释
    re_href = re.compile(r'<\s*a[^>]*>[^<](.*?)*<\s*/\s*a\s*>') #去出超链接,替换
    re_js = re.compile(r'<\s*script[^>]*>[^<](.*?)*<\s*/\s*script\s*>') #去出 javascript
    re_copyright = re.compile(r'<p\s*align="left">(.*?)</p>') #去出 版权信息 #r'<p\s*align="left">' 注意处理换行要

    info = re_zhushi.sub('',info,re.S)
    info = re_href.sub(domain,info,re.S)
    #print content
    #exit()
    info = re_copyright.sub(u"",info,re.S)
    info = info.replace(u'\xa0', u' ') #防止gbk转btf输出错误
    #print info
    return info

#处理结果
def caiji_result():
    article_list = get_article_list()
    #print article_list
    #判断是否数据库中是否有,是否写入数据库
    for article in article_list:
        #print res_check(article)
        #判断是否需要写入
        if not res_check(article):
            #print "no" #u"不存在需要写入"
            res_insert(article)
            #写入后需要发布文章
            body = res_content(article[0])
            send_article(title = article[1],body = body)
        else:
            #print "yes" #u"已经存在不需要写入"
            pass
#爬虫调用函数
def start():
    caiji_result()

__init__.py用于发布模块时用。

写完了、是不是发现和scrapy基础功能有点像呢。。。

利用Python合并IIS大日志

想用星图分析日志,可是日志是每天一份,一共10几份如果一份一份分析太慢,而且结果也不理想,想要多天的日志一起分析,星图没有提供这个功能,自由自己想办法合并下日志了。
然后用python写了个合并脚本的日志,记录下:

#!/usr/bin/python  
#coding:utf8
import os,sys

fo = open('all.txt', 'w')
for name in ['1.txt','2.txt',]:
    fi = open(name)
    while True:
        s = fi.read(16*1024)
        if not s:
            break
        fo.write(s)
    fi.close()
fo.close()

这样的话会存在一个问题。1.txt的结尾和2.txt的开头合并没有换行,可以在循环外添加一个日志格式的标识,不破坏日志的结构,看了下IIS的日志头是:

#Software: Microsoft Internet Information Services 7.5
#Version: 1.0
#Date: 2016-09-04 00:00:00
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent)

这样的话#会注释掉,可以不用追加日志标识。合并的过程中,如果有一个日志文件的日志结构不对应,则会中断,需要所有日志结构都是一样的,跑了一下有错误。一份日志也比较大,没有去找文件中存在问题的哪一行,直接用二分法把日志合并为两份就ok了,如果还是不行的话就分为4份,先找到有问题的日志文件,再进一步定位存在问题的行去孑孓问题。

Python使用sqlite和Mysql数据库笔记

Python使用sqlite如下:
创建sqlite语句:

CREATE TABLE history (
id??? INTEGER???????? PRIMARY KEY ASC AUTOINCREMENT,
url?? VARCHAR( 100 ),
title TEXT,
date? DATETIME??????? DEFAULT ( ( datetime( ‘now’, ‘localtime’ )? )? )
);

import sqlite3
#建立数据库连接
conn = sqlite3.connect(“db.dll”)
#创建游标
cur = conn.cursor()

#增加
exec_insert = “INSERT INTO history (url,title) VALUES (‘%s’,’%s’)”
cur.execute(exec_insert % (“url2″,”title2”))
conn.commit()

#修改
test_url = “http://127.0.0.2/”
test_title = “dedecms by python spiders!”
exec_update = “UPDATE history SET url=’%s’, title=’%s’ WHERE url=’%s’ AND title=’%s’ ”
cur.execute(exec_update % (test_url,test_title,”url2″,”title2″))
conn.commit()
#MD,开始因为创建了索引、测试半天没能修改、、、

#删除
cur.execute(“DELETE FROM history WHERE id = 1”)
conn.commit()

#查询
exec_select = cur.execute(“select * from history”)
print cur.fetchall()

 

Python使用mysql如下:

import MySQLdb
#建立数据库连接
conn = MySQLdb.connect(
host = ‘localhost’,
user = ‘root’,
passwd = ‘root’,
db = ‘android’,
port = 3306,
charset =’utf8′,
)
cur = conn.cursor()

#增删改查直接用 %s 替换sql语句就行
“”” –MySQLdb
CREATE DATABASE p2p DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE TABLE `android`.`p2p_caiji` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`url` text,
`keywords` text,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
“””
sqli_select = “SELECT * FROM p2p_caiji WHERE url = %s” #查询是否有存在的记录 sql模版
sqli_insert = “INSERT INTO p2p_caiji (id,url,keywords,date) VALUES(NULL,%s,%s,CURRENT_TIMESTAMP)” #添加记录 sql模版

#查询
exec_select = cur.execute(sqli_select,url)

#添加
cur.execute(sqli_insert,(res[‘url’],res[‘key’]))
conn.commit() #提交事物

修改和删除一样,使用sql模版 %s 替换即可。

python批量抓取代理IP使用requests验证

# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import sys,requests,lxml,re
#设置 utf8 字符流处理
reload(sys)
sys.setdefaultencoding('utf-8')

#设置头信息
headers={       "User-Agent":"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36",
                "Accept":"*/*",
                "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
                "Accept-Encoding":"gzip, deflate",
                "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
                "X-Requested-With":"XMLHttpRequest",
                "Connection":"keep-alive"
        }

#代理验证,proxies() #传入一个字典
def proxies(urls = {"http":"http://124.240.187.78:81"} ):
    proxies = urls
    # timeout=60 设置超时时间60秒
    # res.status_code 查看返回网页状态码
    # verify = False 忽略证书
    try:
        res = requests.get(url = "http://1212.ip138.com/ic.asp",proxies = proxies, verify = False,timeout=60,headers = headers)
        #print u"访问畅通!!!"
        #print res.content
        if res.status_code == 200 :
            #print u"代理可用!"
            #print res.content
            ##with open("1.txt",'wb') as f:
            ##    f.write(res.content)
            print urls
            print u"访问没有问题,返回1"
            return proxies
        else:
            print urls
            print u"访问不可用,返回0"
            return False
    except Exception, e:
        print urls
        print u"访问异常,返回0"
        return False

#获取列表页数 并 生成列表超链接
def get_list_page(listurl = "http://www.xicidaili.com/nt/"):
    #获取列表页数
    doc = requests.get(url = listurl,headers = headers).text
    soup = BeautifulSoup(doc,'lxml')
    page_html = soup.find("div",class_="pagination")
    page_list = re.findall(r"\d+",str(page_html))
    page_max = int(page_list[-2])
    #生成列表超链接
    list_all = []
    for i in xrange(1,page_max+1):
        url =  re.sub('/\d+','/%d'%i,listurl+"1",re.S)
        #print url
        list_all.append(url)
    else :
        #print list_all
        return list_all


#抓取页面字段
def page_data(url = "http://www.xicidaili.com/nn/1"):
    resule = []
    html = requests.get(url,headers = headers).text
    soup = BeautifulSoup(html,'lxml')
    table = soup.select('table tr')
    for tr in table:
        #print tr
        td = tr.select('td')
        iplist = []
        for ip in td:
            #print ip.string
            iplist.append(ip.string)
        #print iplist
        if iplist :
            resule.append(iplist[5].lower() + ':' + iplist[5].lower() + '://' + iplist[1] + ':' + iplist[2])
    return resule
    #获取数据

#追加保存数据
def save_ip(ip):
    with open('ip.txt', 'a') as f:
        f.writelines(ip)
        f.close()

#proxies()
#print get_list_page("http://www.xicidaili.com/nn/")
#print page_data()

list_url = get_list_page(listurl = "http://www.xicidaili.com/nt/")
for url in list_url:
    iplist = page_data(url)
    #print iplist
    #exit()
    for ip in iplist:
        arr = re.split(':',ip)
        #print type(arr),arr,arr[0],arr[1],arr[2],arr[3]
        parame = {arr[0]:arr[1]+':'+arr[2]+':'+arr[3]}
        res = proxies(parame)
        if res :
            #print u"file_put" #写入文件
            save_ip(str(arr[1]+':'+arr[2]+':'+arr[3])+"\r\n")
        else:
            #访问不可用时走这里的流程
            pass


if __name__ == '__main__':
    #print "main"
    pass


# http://www.xicidaili.com/nn/ #国内高匿代理
# http://www.xicidaili.com/nt/ #国内普通代理
# http://www.xicidaili.com/wn/ #国外高匿代理
# http://www.xicidaili.com/wt/ #国外普通代理

Python获取Android Apk签名信息

#!/usr/bin/python
#coding:utf-8
import sys,os,commands,re
reload(sys)
sys.setdefaultencoding('utf8')

def get_signature(file = "test.apk") :
    #resule = commands.getstatusoutput("pwd")
    #查找cert在apk路径
    comm_path = "jar tf " + file + " | grep RSA"
    path = commands.getstatusoutput(comm_path)[1]
    #解压证书文件
    comm_unzip = "jar xf " +? " " + file + " " +? path
    unzip = commands.getstatusoutput(comm_unzip)
    #提取证书信息
    comm_cert = "keytool -printcert -file " + path
    cert = commands.getstatusoutput(comm_cert)[1]
    #删除解压的文件
    comm_rm = "rm -rf " + path
    rm_del = commands.getstatusoutput(comm_rm)
    #返回证书信息
    return cert

#demo1 = get_signature("162b81bea7cf22b5cfb182f991f6b124.apk")
#print demo1
#demo2 = get_signature("com.laijin.simplefinance.apk")
#print demo2
#demo3 = get_signature("com.laijin.simplefinance_043204.apk")
#print demo3

#demo1 = get_signature("8.apk")
#print demo1
#demo2 = get_signature("7.apk")
#print demo2
#demo3 = get_signature("6.apk")
#print demo3

demo3 = get_signature("6.apk")
print demo3

"""
test = demo3
rex = u"[\xe5\xba\x8f\xe5\x88\x97\xe5\x8f\xb7:]"+"(.*?)"+u"[\\xe6\x9c\x89\xe6\x95\x88\xe6\x9c\x9f:]"
regx = re.compile(rex)
s2 = regx.findall(test) #([\u5e8f\u5217\u53f7\u003a])+(.*?)+([\u5e8f\u5217\u53f7])
print s2
"""

#获取签名键值
def get_value(line):
    index = line.find(':') #第一次出现的位置
    resule = line[index+1:] #第一次出现的位置截止后的字符串
    return resule

#过滤获取签名返回值
def resule_signature(signature):
    #定义返回结果
    resule ={}
    #定义分割的每行数据
    lines = []
    #分割每一行生成list
    for line in signature.split("\n"):
    lines.append(line)
    #print lines #打印签名序列
    resule['suoyouzhe'] = get_value(lines[0])
    resule['qianfaren'] = get_value(lines[1])
    resule['xuliehao'] = get_value(lines[2])
    resule['youxiaoqi'] = get_value(lines[3])
    resule['zhengshu'] = {}
    resule['zhengshu']['md5'] = get_value(lines[5])
    resule['zhengshu']['sha1'] = get_value(lines[6])
    resule['zhengshu']['suanfa'] = get_value(lines[7])
    resule['zhengshu']['version'] = get_value(lines[8])
    return resule

    resule = resule_signature(demo3)

"""
#提取序列号
xuliehao = lines[2]
"""
#获取签名键值
def get_value(arr):
    value = []
    index = arr.find(':')
    print index

    for line in arr.split(":"):
    value.append(line)
    value = value[1]
    print u">>>>>>>>>>>>",value
    return value

Scrapy爬虫框架安装使用笔记

#学习网址
#http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html

scrapy startproject pachong #创建项目
scrapy genspider AppVersion itunes.apple.com #创建爬虫 scrapy genspider 文件名 爬取URL链接

scrapy list #查看当前项目下有几个爬虫,需要进入项目目录后运行 scrapy list 命令

把AppVersion.py拖入 pachong/pachong/spiders 文件夹下
scrapy crawl AppVersion #启动爬虫项目 name = “AppVersion”

#ImportError: No module named items 报错说明创建的爬虫不能和项目名称相同,或者_区分也不行

#XPath表达式
/html/head/title: 选择HTML文档中 <head> 标签内的 <title> 元素
/html/head/title/text(): 选择上面提到的 <title> 元素的文字
//td: 选择所有的 <td> 元素
//div[@class=”mine”]: 选择所有具有 class=”mine” 属性的 div 元素

#使用实例:version = response.xpath(“//span[@itemprop=’softwareVersion’]/text()”).extract()
#Xpath出来的是列表哦,要取列表的值
scrapy crawl AppVersion -o items.json #保存为JSON

scrapy list #检查当前项目可用爬虫列表
scrapy runspider AppVersion.py #运行一个爬虫

ITEM_PIPELINES = {? ‘pachong.pipelines.PachongPipeline’: 300,} #使用pipelines配置
#使用日志
LOG_ENABLED = True
LOG_ENCODING = ‘utf-8’
LOG_FILE = ‘log.txt’ #添加绝对路径,否则报错!
LOG_LEVEL = ‘DEBUG’
LOG_STDOUT = True
####使用日志后,命令行不会打印信息了
CRITICAL – 严重错误(critical)
ERROR – 一般错误(regular errors)
WARNING – 警告信息(warning messages)
INFO – 一般信息(informational messages)
DEBUG – 调试信息(debugging messages)

USER_AGENT = ‘Mozilla/7.0 (compatible; Baiduspider/3.5; +http://www.baidu.com/search/spider.html)’
#模拟百度访问

ROBOTSTXT_OBEY = True #是否检查 robots.txt

#Items相关
product = Product(name=’jiage’, price=100) #创建字段
product[‘name’]或product.get(‘name’) # 获取字段值
product[‘last_updated’] = ‘today’ #设置字段值
product.keys() #获取所有字段值
product2 = Product(product) #复制item
dict(product) #根据item创建字典(dict)
Product({‘name’: ‘Laptop PC’, ‘price’: 1500}) #根据字典(dict)创建item

##Scrapy自带的发邮件貌似不好用,配置半天也没成功,之后自己写了个邮件方法

用Scrapy编写一组app版本监控的爬虫

首先创建Mysql数据库、表、字段、如下:

CREATE DATABASE jiankong_db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE TABLE `jiankong_db`.`app_version` (
`id` int(10) unsigned  NOT NULL  AUTO_INCREMENT,
`version` text,
`url` text,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

修改配置文件settings.py

#自定义USER_AGENT
USER_AGENT = 'Mozilla/7.0 (compatible; Baiduspider/3.5; +http://www.baidu.com/search/spider.html)'

#日志配置
LOG_ENABLED = True
LOG_ENCODING = 'utf-8'
LOG_FILE = 'log.txt'
LOG_LEVEL = 'INFO'
LOG_STDOUT = True

#配置使用Pipelines
ITEM_PIPELINES = {
'pachong.pipelines.PachongPipeline': 300,
}

爬虫类的回调函数 Spiders/AppVersion.py

import scrapy
#from 项目名称.items import 项目Item类名
from pachong.items import PachongItem
class AppversionSpider(scrapy.Spider):
    name = "AppVersion" #定义项目名称
    allowed_domains = ["itunes.apple.com"]
    start_urls = (
    "https://itunes.apple.com/cn/app/jian-li-cai-cai-fu-guan-li/id987830667", #app1,
    "https://itunes.apple.com/cn/app/yin-ke-li-cai-tou-zi-li-cai/id879768943", #app2
    )

    def parse(self, response):
        item = PachongItem() #创建item.py类实例
        item['version'] = response.xpath("//span[@itemprop='softwareVersion']/text()").extract()[0]
        #.encode("utf-8")
        item['url'] = response.url
        #item['date'] = time.time() #time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) 时间戳转换函数
        #print u"@输出信息开始@"
        #print item['version']
        #print u"@输出信息结束@"
        yield item

配置返回字段映射 items.py

import scrapy
class PachongItem(scrapy.Item):
    version = scrapy.Field() #定义版本字段
    url = scrapy.Field() #定义软件url版本
    #date = scrapy.Field() #定义抓取当前版本的时间

配置返回处理 pipelines.py

import MySQLdb
import smtplib
from email.mime.text import MIMEText
class PachongPipeline(object):
    def connect(self):
        #建立数据库连接
        conn = MySQLdb.connect(
        host = 'localhost',
        user = 'root',
        passwd = 'root',
        db = 'jiankong_db',
        port = 3306,
        charset='utf8'
        )
        return conn

    #发送邮件函数send_mail(收件,标题,内容)
    def send_mail(self,shoujian,title,body):
        # 设置服务器,用户名、密码以及邮箱的后缀
        mail_user = "610358898"
        mail_pass="填写密码"
        mail_postfix="qq.com"
        me=mail_user+"<"+mail_user+"@"+mail_postfix+">"
        msg = MIMEText(body, 'html', 'utf-8')
        msg['Subject'] = title
        #msg['to'] = shoujian
        try:
            mail = smtplib.SMTP()
            mail.connect("smtp.qq.com")#配置SMTP服务器
            mail.login(mail_user,mail_pass)
            mail.sendmail(me,shoujian, msg.as_string())
            mail.close()
            print u"send mail success!"
        except Exception, e:
            print str(e)
            print u"send mail exit!"

        #回调函数返回
    def process_item(self, item, spider):
        conn = self.connect()
        cur = conn.cursor()
        print u"测试最新抓到的数据:",item['version'],item['url']
        #查询是否有存在的记录 sql模版
        sqli_select = "SELECT * FROM app_version WHERE version = %s AND url = %s"
        #添加记录 sql模版
        sqli="INSERT INTO app_version (id,version,url,date) VALUES(NULL,%s,%s,CURRENT_TIMESTAMP)"
        result = cur.execute(sqli_select,(item['version'],item['url']))
        print u"返回结果:",result
        if result print u"准备插入了!"
        body = "VERSION:" + str(item['version']) + "<br>" + "URL:" + str(item['url'])
        """
        #发邮件,如果发不出则用自己的邮件方法处理
        mailer.send(
        to=["admin@0535code.com"],
        subject="IOS APP 版本监控邮件通知",
        body= body,
        )
        """
        cur.execute(sqli,(item['version'],item['url']))
        conn.commit() #提交事物
        conn.close() #关闭数据库连接
        #关闭数据库后,发邮件通知
        self.send_mail(shoujian = "454690484@qq.com", title = "IOS APP版本更新通知!" , body = body)

########测试了Scrapy自带的发邮件的配置了半天没用了,官网写的很简单,配起来各种问题,发现问题比较少的爬虫,在不熟悉Scrapy的情况下,用纯Python可能会更快一些,也重写了一个Python原声版的,而且会一直在内存中跑,遇到问题则会自动发邮件,代码如下########

import sys,os,requests,time,logging,re,random,lxml,smtplib
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
import MySQLdb
#解决输出问题
reload(sys)
sys.setdefaultencoding( "utf-8" )
#设置头信息,用于抓取页面的内容
headers={       "Host":"itunes.apple.com",
"User-Agent":"Mozilla/7.0 (compatible; Baiduspider/3.5; +http://www.baidu.com/search/spider.html)",
"Accept":"*/*",
"Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding":"gzip, deflate",
"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With":"XMLHttpRequest",
"Connection":"keep-alive"
}
#定义访问cookies实例
sid = requests.session()
#定义爬虫数组
urls = [
"https://itunes.apple.com/cn/app/jian-li-cai-cai-fu-guan-li/id987830667",
"https://itunes.apple.com/cn/app/yin-ke-li-cai-tou-zi-li-cai/id879768943",
]
#定义数据库ORM字典
results = {}
#建立数据库连接
conn = MySQLdb.connect(
host = 'localhost',
user = 'root',
passwd = 'root',
db = 'jiankong_db',
port = 3306,
charset='utf8'
)
cur=conn.cursor()
sqli_select = "SELECT * FROM app_version WHERE version = %s AND url = %s" #查询是否有存在的记录 sql模版
sqli="INSERT INTO app_version (id,version,url,date) VALUES(NULL,%s,%s,CURRENT_TIMESTAMP)" #添加记录 sql模版

#获取版本数据函数
def mouthpiece(url):
    res_html = sid.get(url).content
    html = BeautifulSoup(res_html,'lxml')
    results = html.find("span", {"itemprop":"softwareVersion"}).get_text()
    #print results
    return results

#开始爬取,主函数
def start_app(sleep):
    #遍历爬取url版本
    for url in urls:
    results['url'] = url
    results['version'] = mouthpiece(url)
    #print results
    results_sql = cur.execute(sqli_select,(results['version'],results['url'])) #查询结果,看数据库中是否有值
    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),u"数据库查询返回结果:",results_sql
    if results_sql<1 :
        print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),u"有更新了!"
        cur.execute(sqli,(results['version'],results['url']))
        conn.commit()
        #保存后发邮件通知
        body = "URL:" + results['url'] + "version:" + results['version']
        send_mail(shoujian = "454690484@qq.com" , title = "APP版本更新通知!" , body = body)
    else:
        print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),u"没有更新!",results['url'],results['version']
        time.sleep(sleep)
        start_app(sleep)

#发送邮件函数send_mail(收件,标题,内容)
def send_mail(shoujian,title,body):
    # 设置服务器,用户名、密码以及邮箱的后缀
    mail_user = '610358898@qq.com'
    mail_pass="写自己邮箱密码"
    mail_postfix="qq.com"
    me=mail_user+"<"+mail_user+"@"+mail_postfix+">"
    msg = MIMEText(body, 'html', 'utf-8')
    msg['Subject'] = title
    #msg['to'] = shoujian
    try:
        mail = smtplib.SMTP()
        mail.connect("smtp.qq.com")#配置SMTP服务器
        mail.login(mail_user,mail_pass)
        mail.sendmail(me,shoujian, msg.as_string())
        mail.close()
        print u"send mail success!"
    except Exception, e:
        print str(e)
        print u"send mail exit!"

#send_mail(shoujian = "admin@0535code.com",title = "test",body = u"测试内容")

def c_main():
    try:
        print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + u" ------开始解析执行监控..."
        start_app(6)
        #每10分钟执行一次
    except:
        #打印错误日志
        print "Unexpected error:",sys.exc_info()
        logging.basicConfig(filename='error.log')
        logging.exception("Exception Logged")
        time.sleep(10)#如果遇到问题睡眠10秒钟
        #start_app(600)
        send_mail( shoujian = "admin@0535code.com",title = "IOS APP版本监控BUG反馈",body = str(sys.exc_info()) )
        c_main()

#MAIN方法
if __name__ == "__main__":
    c_main()

这是后面增加代码功能整理的格式、如果有问题、欢迎吃瓜群众留言

Python常用库安装汇总

安装easy_install
下载地址:https://pypi.python.org/pypi/ez_setup
解压,安装 python ez_setup.py

安装pip
下载地址:https://pypi.python.org/pypi/pip
解压,安装 python setup.py install
linux下安装依赖setuptools库:
wget http://pypi.python.org/packages/source/s/setuptools/setuptools-2.0.tar.gz
tar zxvf setuptools-2.0.tar.gz
cd setuptools-2.0
python setup.py build
python setup.py install
wget https://pypi.python.org/packages/e7/a8/7556133689add8d1a54c0b14aeff0acb03c64707ce100ecd53934da1aa13/pip-8.1.2.tar.gz#md5=87083c0b9867963b29f7aba3613e8f4a
cd pip-1.4.1/
sudo python setup.py install
########################在安装python2.7.9时如果选择了pip上面就不用安装了,否则按照上面流程安装pip#########

安装requests库

cd 到 C:\Python27\Scripts> 目录
执行命令 pip install requests
测试 import requests

安装 lxml
执行命令 pip install lxml
测试 import lxml,
在win7下安装有时会有问题,直接去官网下载exe安装好了:https://pypi.python.org/pypi/lxml/3.6.0

安装 beautifulsoup4
执行命令 pip install beautifulsoup4
测试 from bs4 import BeautifulSoup

python编译py为pyc文件 python -m py_compile demo.py
或者
import compileall
compileall.compile_dir(r’/home/root/Desktop/demo.py’)

安装py2exe 官网下载链接:http://www.py2exe.org/
在python的目录下面,通常是(C:\Python27,看你安装Python的位置)建立setup.py文件,文件中输入以下代码:
from distutils.core import setup
import py2exe
setup(console=[“将要转换的文件名称.py”])
从终端(cmd)进入Python27目录,输入以下命令
python setup.py py2exe
这样便完成了从.py文件到 .exe文件的转换
生成的软件在dist文件夹内
如果用到了lxml库,则应该用 python setup.py pyexe -p lxml,gzip 命令,否则会报错!

 

安装Scrapy #经过验证,在win下需要很多依赖库,比较麻烦

1.安装twisted,需要先安装下面的依赖库
#项目路径:sourceforge.net/projects/pywin32/files/

A.安装zope.interface
下载链接:https://pypi.python.org/pypi/zope.interface#download
我是win32系统,下载下面的链接EXE文件直接安装了,
https://pypi.python.org/packages/43/a3/7092ca779bf09a50128c45875700ecff55db2de0a98e5ab969b73bdf5e7a/zope.interface-4.2.0.win32-py2.7.exe#md5=e816efeac869c956d1d1da7a985dab8c
#安装完后 import zope.interface,验证是否安装成功

B.安装pyopenssl
下载链接:https://pypi.python.org/pypi/pyOpenSSL#downloads
这里只有两个,一个whl在线安装的,一个离线安装的,我下载了第一个whl在线安装的,
pip install C:\Users\Administrator\Desktop\pyOpenSSL-16.0.0-py2.py3-none-any.whl
有的人没有设置Python27/Scripts环境变量,要CD切换到Scripts目录去执行
安装完了,貌似安装了好几个东东进去,Successfully installed cffi-1.7.0 cryptography-1.4 enum34-1.1.6 idna-2.1 ipaddre ss-1.0.16 pyOpenSSL-16.0.0 pyasn1-0.1.9 pycparser-2.14setuptools-25.1.0
//上面的只找到32位操作系统的whl包,如果能找到64位的whl包也可以,我找了个msi包:https://www.egenix.com/cryptodownload/?file=egenix-pyopenssl-0.13.0_1.0.0g_1.win-amd64-py2.7.msi
#安装完后 import OpenSSL,验证是否安装成功

C.安装twisted
按照网上说的,找到的是64位whl的,一直安装不成功,本地是32位的,没看到官网32位的,于是重新搜索了一个,下载地址:http://www.newasp.net/soft/77004.html
pip install C:\Users\Administrator\Desktop\Scrapy-1.1.1-py2.py3-none-any.whl
#Installing collected packages: Scrapy, attrs, pyasn1-modules
#Successfully installed Scrapy-1.1.1 attrs-16.0.0 pyasn1-modules-0.0.8
#安装完后 import scrapy,验证是否安装成功

##全部安装成功后,在命令行输入 scrapy 会显示相关使用参数说明。还需要lxml库。。。这里就不写了。。。

linux下安装: pip install Scrapy #貌似linux安装的比win自己分别安装的库多,推荐linux安装
scrapy

在Kali下创建项目报错##raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.ContextualVersionConflict: (pyasn1 0.1.3 (/usr/lib/python2.7/dist-packages), Requirement.parse(‘pyasn1>=0.1.8’), set([‘pyasn1-modules’])),则需要升级下pyasn1,具体执行下面命令:
sudo?apt-get?install?python-pip #安装pip
sudo? pip install –upgrade pip??? #升级pip
sudo? pip install –upgrade pyasn1 #升级pyasn1
scrapy startproject spider_app #创建项目
#root@0535coder:~# scrapy startproject spider_app
#New Scrapy project ‘spider_app’, using template directory ‘/usr/local/lib/python2.7/dist-
#packages/scrapy/templates/project’, created in:
#??? /root/spider_app
#
#You can start your first spider with:
#??? cd spider_app
#??? scrapy genspider example example.com

 

安装django

pip install django

Centos下后台运行Python程序 命令screen

#如果提示锁定执行下面命令
rm -rf /var/run/yum.pid

#安装 screen
yum -y install screen

#启动screen
screen

#查看会话列表
screen -ls

#恢复会话
screen -r 会话ID

使用参数说明
-A  将所有的视窗都调整为目前终端机的大小。
-d <作业名称>  将指定的screen作业离线。
-h <行数>  指定视窗的缓冲区行数。
-m  即使目前已在作业中的screen作业,仍强制建立新的screen作业。
-r <作业名称>  恢复离线的screen作业。
-R  先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-s  指定建立新视窗时,所要执行的shell。
-S <作业名称>  指定screen作业的名称。
-v  显示版本信息。
-x  恢复之前离线的screen作业。
-ls或–list  显示目前所有的screen作业。
-wipe  检查目前所有的screen作业,并删除已经无法使用的screen作业。

在win下用py2exe编译,把所有动态库也都打包了,通过python compile模块只是编译了当前文件,还需要依赖库,需要装下引用的库: #如果没有pip要先安装下pip,或者提示pip版本过旧,需要更新下。
yum install python-pip && pip install –upgrade pip
pip install requests
yum install libxslt-devel? && pip install lxml
pip install beautifulsoup4

python飞信发短信接口实现

最近做了个乌云漏洞邮件推送,朋友想用短信实现,据现在了解乌云的漏洞,如果收短信的话,每天会收到不少短信,现在推送的邮件也只看看标题,有时候重要资料泄漏的时候,也可以去拿下重要资料,这个很重要哦。说不定以后一些数据会用得到,虽然一直没有用到过的,也没什么数据,今天主要是实现短信接口,不考虑花钱的了,有免费的为嘛不用,记得之前赶集网一直是用的飞信推送的消息,应该是可以利用飞信免费发短信的,其次就是139邮箱也可以短信邮件通知,之前记得用php做一个表单的时候用过139邮箱,限制了发送频率,而飞信没有限制,估计飞信的难度会比139邮箱低一些。决定研究飞信了,网上看了下飞信官方没有api,只有一些破解版的api,试了下破解版的都不生效了。估计是飞信为了不要他们这么做改版或做限制了。通过抓包分析仍然是很容易破解飞信短信接口的,更重要的是飞信在验证手机号的时候还有重放,这么大的一个产品应该完善的好一些吧。可以重放没关系,至少加个随机数,加个验证码,降低被恶意利用。
发短信的HTTP数据包如下:

“””
POST /WebIM/SendMsg.aspx?Version=12 HTTP/1.1
Host: webim.feixin.10086.cn
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://webim.feixin.10086.cn/main.aspx
Content-Length: 91
Cookie: WT_FPC=id=2fcb23760e2cd13e7331459683774250:lv=1459685850316:ss=1459683774250; CmLocation=100|100; CmProvid=bj; mobileNo1=eea9cd7d4a5fc1c3842c95b5597b5bcea80a0c8e@@fab16175347ef6cd6129d6075f9831033a6cd311@@1459683976386; VerificationCode=0e36621b8501448f9299ac8e4eba0c0e; IsCookiesEnable=true; webim_loginCounter=1461335530651; ccpsession=776e58ca-4056-49ef-aa3c-c934f8ef8e2e; webim_usersid=267905802; webim_userstatus=0; webim_login_status=1; webim_remindmsgs=267905802–0-d7b163171d6b447d9c507e24387900a5
Connection: keep-alive

To=1393465590&IsSendSms=1&Msg=111&ssid=952890508p30377-d7b16317-1d6b-447d-9c50-7e24387900a5
“””

下面用python模拟下:

# coding:utf-8
import requests,sys,random
#解决输出问题
reload(sys)
sys.setdefaultencoding( "utf-8" )
#设置头信息
headers={
"Host": "webim.feixin.10086.cn",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://webim.feixin.10086.cn/main.aspx",
"Content-Length": "91",
"Cookie": "WT_FPC=id=2fcb23760e2cd13e7331459683774250:lv=1459685850316:ss=1459683774250; CmLocation=100|100; CmProvid=bj; mobileNo1=eea9cd7d4a5fc1c3842c95b5597b5bcea80a0c8e@@fab16175347ef6cd6129d6075f9831033a6cd311@@1459683976386; VerificationCode=0e36621b8501448f9299ac8e4eba0c0e; IsCookiesEnable=true; webim_loginCounter=1461335530651; ccpsession=776e58ca-4056-49ef-aa3c-c934f8ef8e2e; webim_usersid=267905802; webim_userstatus=0; webim_login_status=1; webim_remindmsgs=267905802--0-d7b163171d6b447d9c507e24387900a5",
"Connection": "keep-alive",
}
#定义访问cookies实例
sid = requests.session()
api = "http://webim.feixin.10086.cn"
#tradeNo = random.randint(11,99)
#API 1
api_1 = api + "/WebIM/SendMsg.aspx?Version=12"
params_1 = {??????????? 'To':'1393465590', #发送人手机号ID
'IsSendSms':'1',
'Msg':'test', #发送的内容
'ssid':'952890508p30377-d7b16317-1d6b-447d-9c50-7e24387900a5',
#appId,key
}
test = requests.post(api_1,params_1,headers = headers)
print test.content

打印出成功响应:{“rc”:200}
预测,目前可能会存在cookies的有效期问题,要保持Cookies的有效时间,针对这个有两种解决方案:
1.如果飞信在服务端没有设置cookies的有效期,则是关闭浏览器后失效的,保持浏览器开着页面的状态就好了,如果做了有效期设置或者访问时效设置,做个客户端定时刷新页面就好了;
2.这个是登陆页面,https://webim.feixin.10086.cn/login.aspx,需要手机接受验证码,可以判断返回信息如果不是200,则去请求验证码,然后输入验证码再次提交保持cookies分析cookies发短信,虽然有点繁琐,但是这种方式能分析出原理。