JAVA爬取亚马逊的商品信息
在程序里面輸入你想爬取的商品名字,就可以返回這件商品在亞馬遜搜索中都所有相關商品的信息,包括名字和價格。
解決了在爬取亞馬遜時候,亞馬遜可以識別出你的爬蟲,并返回503,造成只能爬取幾個頁面的問題。
除此之外亞馬遜網頁代碼寫得非常的亂啊(可能是我個人問題?),要想提取里面的信息非常麻煩。
純JAVA編寫,用的都是java自帶的庫。
先展示一下效果圖:
商品頁面:
?
爬取的信息頁面(消除重復了):
?
名字和價格是絕對正確的,例如上圖31行的商品:
?
主要思路是這樣的:
1、打開搜索的列表頁,然后抽取所有商品頁的url和下一頁的url,加入爬取的隊列。
2、判斷若是列表頁則重復步驟1,若是商品詳細信息的頁面,提取商品名稱和價格到一個文件中。
?
遇到的主要問題:
1、亞馬遜的頁面限制流量,如果在限定的時間內訪問次數太多,就會返回503。一般是爬取幾張頁面后就不能繼續下去了。如圖:
?
解決辦法是:
a、盡量模仿瀏覽器,辦法就是設置User-Agent啦!用一個數組存了 多個User-Agent,然后隨機調用。
b、降速,適當延長兩次請求的時間。
c、去重,重復的url
d、掛代理,這個就算了,太復雜
?
?
2、亞馬遜的代碼很亂!提取有用的信息十分困難。不過細心找還是能發現規律的,我用正則表達式來提取的。
亞馬遜搜索頁面的url(就是搜索商品后回車的頁面):
"http://www.amazon.cn/s/ref=nb_sb_noss?__mk_zh_CN=%E4%BA%9A%E9%A9%AC%E9%80%8A%E7%BD%91%E7%AB%99&field-keywords="+商品名;
對于商品頁面的抽取,商品名字和價格的抽取等等在代碼里面。
?
3、在列表里面會有同一件商品的3~4個url名字,可以跳轉到名字部分,圖文信息部分還有評論部分的。
要判斷如果這些頁面的商品編號相同,就只取一個就好了。例如:
http://www.amazon.cn/%E6%89%8B%E6%9C%BA-%E9%80%9A%E8%AE%AF/dp/B00OB5T26S......
dp后面是商品編號。
?
代碼只爬取了搜索頁的第一頁,因為第一頁的商品最貼近我們想要的東西,而且后面的頁面很多都是重復的或者是不相關的了。
除了我們搜索一個品牌才會有很多頁,一般搜索具體的東西還是第一頁比較靠譜。當然,也可以爬取后面的頁面啦,url在html中,自己提取就行。
?
public class amazon {public static int i=0;//用來儲存上一個商品編號,看有沒有重復public static String last = "|";//匹配商品urlpublic static Pattern p_goods = Pattern.compile("href=\"(http://www(.+?)/dp/(.+?))\"");//存放待爬取的urlpublic static Queue<String> data = new LinkedList<String>();//要輸入到file中public static File file;//15個ua隨機用,減少503的機率public static String [] ua = {"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36","Mozilla/5.0 (Windows NT 6.1; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)","Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1","Opera/9.80 (Macintosh; Intel Mac OS X 10.9.1) Presto/2.12.388 Version/12.16","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68","Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/30.0.1599.12 Mobile/11A465 Safari/8536.25","Mozilla/5.0 (iPad; CPU OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4","Mozilla/5.0 (iPad; CPU OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A501 Safari/9537.53"};public static void action(String target) throws IOException, InterruptedException{//補全targer的搜索頁面if(i==0){target = "http://www.amazon.cn/s/ref=nb_sb_noss?__mk_zh_CN=%E4%BA%9A%E9%A9%AC%E9%80%8A%E7%BD%91%E7%AB%99&field-keywords="+target;i++;}//先打開輸入流URL url = new URL(target);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setRequestMethod("GET");Random index = new Random();String u = ua[Math.abs(index.nextInt()%15)];//System.out.println("us--->"+u);//隨機調用uaconn.setRequestProperty("User-Agent",u);conn.setRequestProperty("Host","www.amazon.cn");conn.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");conn.setRequestProperty("Connection","keep-alive");conn.connect();InputStream in = conn.getInputStream();byte [] buf = new byte[1024];//把數據裝進ByteArrayOutputStream中ByteArrayOutputStream outStream = new ByteArrayOutputStream();int len = 0;while((len=in.read(buf))!=-1){outStream.write(buf,0,len);}in.close();outStream.close();String content = new String(outStream.toByteArray());//判斷頁面類型 Pattern pp_goods = Pattern.compile("http://www(.+?)/dp/(.+)");Matcher m_goods = pp_goods.matcher(target);//如果是商品頁面if(m_goods.find()){System.out.println("This is goods page");//提取名字和價格Pattern p_name = Pattern.compile("<meta name=\"description\" content=\"(.+?),");Matcher m_name = p_name.matcher(content);Pattern p_price = Pattern.compile("class=\"a-size-medium a-color-price\">¥(.+?)</span>");Matcher m_price = p_price.matcher(content);//文件寫操作PrintWriter pw = new PrintWriter(new FileWriter("goods.txt", true));while(m_name.find()){ pw.print(m_name.group(1)+"------->");}while(m_price.find()){ pw.println(m_price.group(1));}pw.close();}//其他就是列表頁面了else{//提取里面的商品urlm_goods = p_goods.matcher(content);int count = 0;//提取這個url的編號Pattern p_num = Pattern.compile("/dp/(.+?)/"); while(m_goods.find()){String current = m_goods.group(1); Matcher m_num = p_num.matcher(current); String current_num = "";if(m_num.find()){current_num = m_num.group(1);//System.out.println(current_num);}//去重!!!!!!!!!//如果不等于上一個商品編號,才將該url加入隊列if(!current_num.equals(last)){//System.out.println(current);//System.out.println(current_num);//System.out.println("goods url");data.add(current);last = current_num; }}}}public static void main(String args[]) throws IOException, InterruptedException{//直接輸入商品名字就好了String target = "macbook pro"; amazon.action(target);//如果隊列非空,則一直進行while(!data.isEmpty()){ amazon.action(data.poll()); }} }?
效果:
才第一頁就已經比較多無用的東西了,比如保護膜什么什么的。我一開始是爬取了很多頁面的,但發現后面都是一些沒用的東西,所以后面的頁面意義不大。
?
其實真正高效的話,還是要用到多線程和一些去重技術,這里只是一個簡單的實例。
總結
以上是生活随笔為你收集整理的JAVA爬取亚马逊的商品信息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试官问你B树和B+树,就把这篇文章丢给
- 下一篇: 强联通分量算法的个人详解Tarjan算法