기능을 간단히 소개하자면
1. JD모바일 일일플래시세일 페이지에서 상품(휴대폰) 링크를 가끔씩(예: 1분) 추출합니다.
http://sale.360buy.com/act/8VTHFGr10CjMDyZ.html#01
2. 추출된 제품 링크를 기반으로 백엔드로 데이터를 전송하여 제품 가격, 설명, 할인, 재고(재고 여부) 및 기타 정보를 얻습니다.
3. 얻은 정보를 바탕으로 판단하십시오.
조건이 만족되면 자동으로 브라우저가 호출되어(환경변수에 크롬을 추가하거나, 코드에 browser.exe 경로를 추가하도록 코드를 변경하고, 프로그램을 수정한 경우) 상품주문을 오픈합니다. 페이지.
4. 사실 이렇게 하면 문제가 해결됩니다. 더 이상 웹 페이지를 자주 새로 고치거나 직접 확인할 필요가 없습니다.
로그인 및 주문 제출은 브라우저에서 해결해야 합니다. (이러한 기능적 사항은 더 복잡하고 처리되지 않은 것 같습니다.)
이 프로그램은 완벽하지 않습니다.
실행하기 전에 수정해야 할 몇 가지 위치가 있습니다.
1. 환경 변수: 크롬은 쉬운 호출을 위해 브라우저 변수를 추가합니다. . 또는 소스 코드를 직접 수정하고 다른 방법으로 열어보세요.
2. 액티비티 내 각 상품의 가격 정보를 설정해야 합니다. 좋지 않습니다. 소스 코드를 수정해야 합니다.
수정 사항은 filter() 함수에 있습니다.
3. 수정해야 할 또 다른 장소는
hasStore(문자열 스퀴드키)
address="http://price.360buy.com/stocksoa/StockHandler.ashx?callback=getProvinceStockCallback&type=pcastock&skuid="+skuidkey+"&provinceid=1&cityid=2800&areaid=2850";
cityid=2800&areaid=...이 장소의 위치 정보입니다. 처리되지 않았습니다. 휴대폰 상품페이지에서 직접 알아내셔야 합니다.
실제로는 비교적 간단합니다. 크롬+F12를 누르면 "도시", 지역 및 기타 정보를 수정한 후 필요한 정보가 포함된 가져오기 요청이 백그라운드로 전송되는 것을 볼 수 있습니다. (http://price.360buy.com/stocksoa/StockHandler.ashx?callback=getProvinceStockCallback&type=pcastock&skuid=64EBD0F20F593D95C72C6EED59B64658&provinceid=1&cityid=2805&areaid=2854) 적절하게 수정하세요.
Util.java
다음과 같이 코드 코드를 복사합니다.
패키지 보기.Util;
import java.util.ArrayList;
공개 클래스 Util {
공개 정적 무효 인쇄(객체 o){
System.out.print(o);
}
공개 정적 무효 println(객체 o){
if(널==o)
System.out.println();
또 다른
System.out.println(o);
}
공개 정적 ArrayList<Integer> toArrayList(int[] ints){
if(ints.length==0)
null을 반환;
ArrayList<Integer> al=new ArrayList<Integer>();
for(int i=0;i<ints.length;i++){
al.add(ints[i]);
}
알을 반환;
}
}
Miaosha360buy.java
다음과 같이 코드 코드를 복사합니다.
패키지 징동;
공개 클래스 Miaosha360buy {
java.util.concurrent.CountDownLatch t= new java.util.concurrent.CountDownLatch(1);
/**
* @param 인수
*/
공개 정적 무효 메인(String[] args) {
// TODO 자동 생성된 메서드 스텁
System.out.println(Thread.currentThread().getName() + "시작");
Miaosha360buy ms360=새로운 Miaosha360buy();
new ThreadOne360buy(ms360.t).start();
동안(참){
노력하다 {
ms360.t.await();
} 잡기(InterruptedException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
노력하다 {
Thread.sleep(1000*60); // 1분마다 호출되나요?
} 잡기(InterruptedException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
ms360.t=새 java.util.concurrent.CountDownLatch(1);
new ThreadOne360buy(ms360.t).start();
System.out.println("새 트레드가 ..");
}
}
}
Miaosha360buy.java
다음과 같이 코드 코드를 복사합니다.
패키지 징동;
공개 클래스 Miaosha360buy {
java.util.concurrent.CountDownLatch t= new java.util.concurrent.CountDownLatch(1);
/**
* @param 인수
*/
공개 정적 무효 메인(String[] args) {
// TODO 자동 생성된 메서드 스텁
System.out.println(Thread.currentThread().getName() + "시작");
Miaosha360buy ms360=새로운 Miaosha360buy();
new ThreadOne360buy(ms360.t).start();
동안(참){
노력하다 {
ms360.t.await();
} 잡기(InterruptedException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
노력하다 {
Thread.sleep(1000*60); // 1분마다 호출되나요?
} 잡기(InterruptedException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
ms360.t=새 java.util.concurrent.CountDownLatch(1);
new ThreadOne360buy(ms360.t).start();
System.out.println("새 트레드가 ..");
}
}
}
ThreadOne360buy.java
다음과 같이 코드 코드를 복사합니다.
패키지 징동;
import java.io.IOException;
import java.util.ArrayList;
java.util.HashMap 가져오기;
java.util.List 가져오기;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
org.apache.http.HttpEntity 가져오기;
org.apache.http.HttpResponse 가져오기;
import org.apache.http.client.ClientProtocolException;
org.apache.http.client.methods.HttpGet 가져오기;
org.apache.http.impl.client.DefaultHttpClient 가져오기;
org.apache.http.util.EntityUtils 가져오기;
org.jsoup.Jsoup 가져오기;
org.jsoup.nodes.Document 가져오기;
org.jsoup.nodes.Element 가져오기;
org.jsoup.select.Elements 가져오기;
import view.Util.Util;
공개 클래스 ThreadOne360buy는 Thread를 확장합니다.
java.util.concurrent.CountDownLatch c;
ArrayList al;//기록 플래시 판매 제품 페이지
부동 가격=0.0f;//제품 가격
float 할인=0.0f;//제품 할인
//스레드 정보를 저장하는데 사용됩니다. 이 프로젝트에서는 별로 유용하지 않습니다.
private static List<Thread> runningThreads = new ArrayList<Thread>();
//이것은 카운터입니다. (사용하는데는 별로 좋지 않습니다. 스레드는 항상 더 복잡하게 느껴졌습니다.)
공개 ThreadOne360buy(java.util.concurrent.CountDownLatch c) {
this.c=c;
}
@보수
공개 무효 실행() {
Register(this);//스레드가 시작될 때 등록
// 시작 태그 인쇄
System.out.println(Thread.currentThread().getName() + "시작...");
노력하다 {
//Jingdong 휴대폰 플래시 판매 페이지를 확인하세요.
this.getMessage("http://sale.360buy.com/act/8VTHFGr10CjMDyZ.html#01");
} 잡기(ClientProtocolException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
c.countDown();
} 잡기(IOException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
c.countDown();
}
c.countDown();
unRegist(this);//스레드가 끝나면 등록 취소
// 종료 태그 인쇄
System.out.println(Thread.currentThread().getName() + "End.");
}
공개 무효 레지스터(스레드 t) {
동기화됨(runningThreads) {
runningThreads.add(t);
}
}
공개 무효 unRegist(스레드 t) {
동기화됨(runningThreads) {
runningThreads.remove(t);
}
}
공개 정적 부울 hasThreadRunning() {
// runningThreads가 비어 있는지 판단하면 아직 실행되지 않은 스레드가 있는지 여부를 알 수 있다.
return (runningThreads.size() > 0);
}
/**
* 모바일 플래시 세일 페이지에서 제품링크, 제품스쿠이드, 스퀴드키, 가격, 매장정보를 확인하세요
* @param url : 모바일 플래시 세일 페이지
* @throws ClientProtocolException
* @throwsIOException
*/
public void getMessage(String url)는 ClientProtocolException, IOException을 발생시킵니다.
al=getMainUrl(down(url));
Util.println(al);
if(al.size()==0){
c.countDown();
시스템.exit(0);
반품;
}
for(int i=0;i<al.size();i++){
StringBuffer sb=new StringBuffer();
StringBuffer openUrl = 새로운 StringBuffer();
openUrl.append("http://www.360buy.com/product/");
openUrl.append(al.get(i).toString().subSequence(al.get(i).toString().lastIndexOf('/')+1, al.get(i).toString().lastIndexOf( '.')));
openUrl.append(".html");
//557673
sb.append("http://d.360buy.com/fittingInfo/get?skuId=");
sb.append(al.get(i).toString().subSequence(al.get(i).toString().lastIndexOf('/')+1, al.get(i).toString().lastIndexOf( '.')));
sb.append("&callback=Recommend.cbRecoFittings");
Util.println(sb.toString());
//지도에 저장되는 것은 제품명, 가격, 할인 정보입니다.
Util.println("Al("+i+") down:"+sb.toString());
HashMap<String, String> hm=parseProduct(down(sb.toString()));
//가격정보 매칭에 사용됩니다. 재고 정보 일치
filter(hm,openUrl.toString());//가격을 필터링하고 조건이 충족되면 브라우저를 엽니다.
}
}
/**
* 확인 방법
* @param hm은 가격 정보를 담고 있습니다.
* @param url 상품페이지
*/
public void filter(HashMap<String, String> hm,String url){//url은 제품 페이지입니다.
//view.Util.oenCMD.openWinExe(null,url);
//인벤토리를 먼저 확인해볼까요?
문자열 skuidkey=parseSkuidkey(url);
if(!hasStore(skuidkey)){
Util.println("---------------");
Util.println("품절!");
Util.println("---------------");
//메인 스레드가 판단할 수 있도록 카운트를 줄입니다.
c.countDown();
//자식 스레드를 종료해야 할까요?
반품;
}
if(hm.get("skuid").equals("201602")){//판단//Motorola skuid=201602
//여기의 가격은 하드코딩되어 있으므로 실행하기 전에 변경해야 합니다.
this.setPrice(499.0f);
//콘솔을 열어야 할까요?
if(Float.parseFloat(hm.get("price"))<=this.getPrice()){
view.Util.oenCMD.openWinExe(null,url);
}
}else if(hm.get("skuid").equals("675647")){//Tianyu skuid=675647
////여기의 가격은 하드코딩되어 있으므로 실행하기 전에 변경해야 합니다.
//this.setPrice(699.0f);
////콘솔을 열어야 할까요?
//if(Float.parseFloat(hm.get("price"))<=this.getPrice()){
//view.Util.oenCMD.openWinExe(null,url);
//}
}
}
/**
* 상품 페이지의 이름, skuid, 가격 정보를 파싱했습니다.
* @paramdoc
* @반품
*/
공개 정적 HashMap<String, String> 구문 분석(문서 문서){
문자열 텍스트=doc.text();
String docc=text.substring(text.indexOf("master")+9,text.indexOf("fittings")-3).replaceAll("[//s]", "");
String[] ss=docc.split(",");
HashMap<String, String> hm=new HashMap<String, String>();
for(문자열: ss){
String string=it.replaceAll("/"", "");
if(string.contains("//u"))
문자열=unicodeDecode(문자열);
String[] str=string.split(":");
hm.put(str[0], str[1]);
}
Util.println(hm);
흠을 반환;
}
/**
* 유니코드 문자를 처리하여 표시문자(한자)로 변환하는데 활용도가 매우 낮습니다.
* @param it: /u6a5d
* @반품
*/
public static String unicodeDecode(String it){//한 가지 단점은 이전 문자를 제거할 수 없다는 것입니다.
Util.println(it);
문자열 정규식="(////u[0-9a-f]{4})";
패턴 pt= Pattern.compile(regex);
매칭엠씨;
StringBuffer sb;
StringBuffer sba=new StringBuffer();
mc=pt.matcher(it);
동안(mc.find()){
sb=new StringBuffer();
mc.appendReplacement(sba,sb.append((char)Integer.parseInt((mc.group(1).substring(2)), 16)).toString());
}
sba.toString()을 반환합니다.
}
/**
* 문서 객체 반환(다운로드 콘텐츠)
* @param url 다운로드 페이지
* @반품
* @throws ClientProtocolException
* @throwsIOException
*/
public static Document down(String url)이 ClientProtocolException, IOException을 발생시킵니다.
문서 문서 = null;
DefaultHttpClient httpClient=new DefaultHttpClient();
Util.println("DownLoad:"+url);
HttpGet get=new HttpGet(url);
HttpResponse 응답;
응답 = httpClient.execute(get);
HttpEntity 엔터티 = response.getEntity();
doc = Jsoup.parse(entity.getContent(), "utf-8","");
//리소스 해제
EntityUtils.consume(엔티티);
//연결을 닫습니다.
httpClient.getConnectionManager().shutdown();
문서를 반환합니다.
}
/**
* 인코딩 제어 정보 추가
* @param 다운로드할 URL 페이지
* @param 코드 인코딩
* @반품
* @throws ClientProtocolException
* @throwsIOException
*/
공개 정적 문서 다운(문자열 URL, 문자열 코드)에서 ClientProtocolException, IOException이 발생합니다.
문서 문서 = null;
DefaultHttpClient httpClient=new DefaultHttpClient();
Util.println("DownLoad:"+url);
HttpGet get=new HttpGet(url);
HttpResponse 응답;
응답 = httpClient.execute(get);
HttpEntity 엔터티 = response.getEntity();
doc = Jsoup.parse(entity.getContent(), 코드,"");
//리소스 해제
EntityUtils.consume(엔티티);
//연결을 닫습니다.
httpClient.getConnectionManager().shutdown();
문서를 반환합니다.
}
/**
* 플래시 세일 페이지의 상품(컬렉션) 링크를 분석하는데 사용됩니다.
* @paramdoc
* @반품
*/
공개 정적 ArrayList<String> getMainUrl(문서 문서){
if(doc.equals("")||doc==null)
null을 반환;
노력하다 {
Thread.sleep(50);
} 잡기(InterruptedException e1) {
// TODO 자동 생성된 캐치 블록
e1.printStackTrace();
}
ArrayList<String> urls=new ArrayList<String>();
String rule="map[name=Map] >area[href~=product]";
/**
* 파싱 시작
*/
요소 elements=doc.select(rule);
for (요소 e : 요소) {
//Util.println(e.absUrl("abs:href"));
urls.add(e.absUrl("abs:href"));
}
반환 URL;
}
/**
* 제품 재고 정보 조회를 위한 skuidkey 획득
* @param URL
* @반품
*/
공개 정적 문자열 구문 분석Skuidkey(문자열 URL){
문서 문서=null;
노력하다 {
doc=down(url,"gb2312");
} 잡기(ClientProtocolException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
} 잡기(IOException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
//Util.println(doc.select("스크립트"));
문자열 텍스트 = null;
for(요소 e : doc.select("script")){
if(e.data().contains("skuidkey:")){
텍스트=e.data();
부서지다;
}
}
//skuidkey:'7D45919EA8242511DAA5CC7C6D7B351C'
text=text.substring(text.indexOf("skuidkey:")+10, text.indexOf("skuidkey:")+42);
Util.println("----------------------");
Util.println(text);
텍스트 반환;
}
/**
* 재고 정보 보기
* @param 스퀴드키
* @반품
*/
public static boolean hasStore(String skuidkey){//이 곳은 처리되지 않으며 브라우저에서 직접 정보를 추출합니다.
문자열 주소 = null;
부울 hasStore=false;
if(skuidkey!=null && !"".equals(skuidkey))
address="http://price.360buy.com/stocksoa/StockHandler.ashx?callback=getProvinceStockCallback&type=pcastock&skuid="+skuidkey+"&provinceid=1&cityid=2800&areaid=2850";
또 다른{
Util.println("skuidkey 구문 분석 중 오류 발생");
}
노력하다 {
if(parseStore(다운(주소))){
hasStore=true;
}
} 잡기(ClientProtocolException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
} 잡기(IOException e) {
// TODO 자동 생성된 캐치 블록
e.printStackTrace();
}
hasStore를 반환합니다.
}
/* if(array[1]=="34"||array[1]=="18"){
ChangeCart(false);
djdarea.stockInfoDom.html("<strong class='store-over'>품절</strong>");
}
else if(배열[1]=="0"){
ChangeCart(false);
djdarea.stockInfoDom.html("<strong class='store-over'>품절</strong>");
}
else if(array[2]=="0"&&array[4]!="2"){
ChangeCart(false);
djdarea.stockInfoDom.html("죄송합니다. 선택하신 지역으로는 배송이 불가능한 상품입니다.");
}
else if(배열[1]=="33"||배열[1]=="5"){
ChangeCart(true);
djdarea.stockInfoDom.html("<strong>자리</strong>"+(array[4]=="1"?", 지역"+(array[3]=="0"?"No":" ")+"대금 상환 지원":"")+cashdesc);
}
else if(배열[1]=="36"){
ChangeCart(true);
djdarea.stockInfoDom.html("<strong>예약</strong>"+(array[4]=="1"?", 지역"+(array[3]=="0"?"No":" ")+"대금 상환 지원":"")+cashdesc);
}
else if(배열[1]=="39"){
ChangeCart(true);
djdarea.stockInfoDom.html("<strong>운송 중</strong>"+(array[4]=="1"?", 지역"+(array[3]=="0"?"No": " ")+"대금 상환 지원":"")+cashdesc);
}
else if(배열[1]=="40"){
ChangeCart(true);
djdarea.stockInfoDom.html("<strong>배포 가능</strong>"+(array[4]=="1"?", 이 지역"+(array[3]=="0"?"No" :"")+"대금 상환 지원":"")+cashdesc);
}
*/
/**
* 재고 정보 분석
* @paramdoc
* @반품
*/
공개 정적 부울 구문 분석 저장소(문서 문서){
문자열 텍스트=doc.text();
String docc=text.substring(text.indexOf("-")-1,text.lastIndexOf(",")-1);
Util.println(docc);
String[] store=docc.split("-");
if(store[1].equals("34") || store[1].equals("18")){
//품절
Util.println("여기 재고가 없습니다.");
거짓을 반환;
}else if(store[1].equals("33") || store[1].equals("5")){
//현물품
Util.println("여기 재고가 있습니다.");
사실을 반환;
}
Util.println(store[1]);
거짓을 반환;
}
//여러 빈 메소드
공개 부동 getPrice() {
반품 가격;
}
공공 무효 setPrice(부동 가격) {
this.price = 가격;
}
공공 부동 getDiscount() {
반품 할인;
}
public void setDiscount(부동 할인) {
this.할인 = 할인;
}
}
oenCMD.java
다음과 같이 코드 코드를 복사합니다.
패키지 보기.Util;
공개 클래스 oenCMD {
//공개 정적 무효 main(String[] args) {
//// openWinExe(null);
// openExe(null,"http://www.baidu.com");
// }
//Java를 사용하여 메모장, calc 등 Windows 시스템의 exe 파일을 호출합니다.
공개 정적 무효 openWinExe(문자열 명령, 문자열 URL) {
if(command==null ||command.equals("")){
명령 = "크롬"+url;
}
런타임 rn = Runtime.getRuntime();
프로세스 p = null;
노력하다 {
p = rn.exec(명령어);
} 잡기(예외 e) {
System.out.println("win exec 오류 발생!");
}
}
//직접 만든 exe나 다운로드하여 설치한 소프트웨어 등 기타 실행 파일을 호출합니다.
공개 정적 무효 openExe(문자열 pathAndName,문자열 url) {
if(pathAndName==null || pathAndName.equals("")){
pathAndName="C://Users//Administrator//AppData//Local//Google//Chrome//Application//chrome.exe";
}
if(url!=null && !url.equals("")){
pathAndName+=" ";
pathAndName+=url;
}
런타임 rn = Runtime.getRuntime();
프로세스 p = null;
노력하다 {
p = rn.exec(pathAndName);
} 잡기(예외 e) {
System.out.println("실행 오류!");
}
}
}