一、基礎版本其實敦煌網是很客氣的網站,基本上沒有做針對的反爬措施,既然別" />
做跨境電商,產品的市場行情是非常關鍵的指標,無論是新品開發(fā)還是市場調研都有需求,那么今天我們就來做個敦煌網的產品價格與銷量查詢的工具。
import requestsfrom bs4 import BeautifulSoupimport refrom urllib.parse import quote_plusimport sysdef save_data(url,path='dhgate.csv',data=None): web_data = requests.get(url) soup = BeautifulSoup(web_data.text,'lxml') prices = [] orders = [] for item in soup.select('#proList .price'): m = re.search(r'(/d*./d*) - (/d*./d*)',item.text) if m: price = float(m.group(1))+float(m.group(2)) prices.append(round(price/2,2)) else: pass for item in soup.select('#proList .attribute'): m = re.search(r'Sold: (/d+)',item.text) if m: orders.append(m.group(1)) else: orders.append(None) for price, order in zip(prices,orders): data = { 'price': price, 'order': order } print(data) with open(path,'a') as f: f.write('{},{}/n'.format(data['price'],data['order']))def get_data(key_word,page_num): key_word = quote_plus(key_word) urls = ['http://www.dhgate.com/w/{}/{}.html'.format(key_word,str(i)) for i in range(page_num)] for url in urls: save_data(url,key_word+'.csv')if __name__ == '__main__': key_word,page_num = sys.argv[1:3] get_data(key_word,int(page_num))
內容比較簡單,為了讓大家不至于看的太累,注釋什么的大多被我刪除了。 下面我們來簡單的講解下這段代碼。 首先,我們導入要用的包:import requests # requests包主要用來獲取網頁內容from bs4 import BeautifulSoup # BeautifulSoup用來解釋網頁內容import re # re包是用正則來輔助解析用from urllib.parse import quote_plus # quote_plus用來處理關鍵詞import sys # sys用來獲取命令行的參數(shù)
主要流程都在__main__
里面,我們通過sys
獲取的關鍵詞和頁數(shù),這里沒有異常處理,其實應該對傳入的參數(shù)進行異常處理下的。然后直接運行get_data
函數(shù)獲取我們所需的數(shù)據(jù)。我們直接在get_data
函數(shù)里調用的save_data
把數(shù)據(jù)存儲到csv
文件中。 這個是最早的版本,大概是在2016寫的,現(xiàn)在運行還是能夠成功。這個版本,只獲取的價格與銷量。import requestsfrom bs4 import BeautifulSoupimport refrom urllib.parse import quote_plusimport sysfrom numpy import meandef save_data(url,path='dhgate.csv',data=None): web_data = requests.get(url) soup = BeautifulSoup(web_data.text,'lxml') info = [] items = soup.find_all("div", "listitem") for item in items: title = item.find("h3").find("a").text # 標題 price = item.find("li","price").text # 價格 m = re.findall(r'(/d+/.*/d+)', price) price = mean(list(map(float, m))) # 計算均價 attribute = item.find("ul", "attribute").text min_order = re.findall(r'Min. Order: (/d+)', attribute)[0] # 起訂量 order = re.findall(r'Sold: (/d+)', attribute) order = order[0] if len(order) > 0 else 0 # 訂單量 feedback = item.find("span","reviewnum") feedback = re.findall(r"/d+", feedback.text)[0] if feedback else 0 seller = list(item.find("span","seller").stripped_strings)[-1] store_url = item.find("span","seller").find("a")['href'] store_feedback = item.find("li","feedback") store_feedback = re.findall(r"/d+/.*/d+", store_feedback.text)[0] if store_feedback else 0 data = { 'title': title, 'price': price, 'min_order': min_order, 'order': order, 'feedback': feedback, 'seller': seller, 'store_url': store_url, 'store_feedback': store_feedback } print(data) with open(path,'a') as f: f.write('{}/t{}/t{}/t{}/t{}/t{}/t{}/t{}/n'.format( data['title'], data['price'], data['min_order'], data['order'], data['feedback'], data['seller'], data['store_url'], data['store_feedback'] ))def get_data(key_word,page_num): key_word = quote_plus(key_word) urls = ['http://www.dhgate.com/w/{}/{}.html'.format(key_word,str(i)) for i in range(page_num)] for url in urls: save_data(url,key_word+'.csv')if __name__ == '__main__': key_word,page_num = sys.argv[1:3] get_data(key_word,int(page_num))
老樣子,簡單講解下,其實主體和第一次寫的沒有太大差別,主要是字段解析這里,多添加了一些內容:for item in items: title = item.find("h3").find("a").text # 標題 price = item.find("li","price").text # 價格 m = re.findall(r'(/d+/.*/d+)', price) price = mean(list(map(float, m))) # 計算均價 attribute = item.find("ul", "attribute").text min_order = re.findall(r'Min. Order: (/d+)', attribute)[0] # 起訂量 order = re.findall(r'Sold: (/d+)', attribute) order = order[0] if len(order) > 0 else 0 # 訂單量 feedback = item.find("span","reviewnum") feedback = re.findall(r"/d+", feedback.text)[0] if feedback else 0 seller = list(item.find("span","seller").stripped_strings)[-1] store_url = item.find("span","seller").find("a")['href'] store_feedback = item.find("li","feedback") store_feedback = re.findall(r"/d+/.*/d+", store_feedback.text)[0] if store_feedback else 0
BeautifulSoup
的css selector
其實還是很好用的,當然,解析速度是相當來說慢了點,不過影響不是太大。后面我們會用lxml
的xpath
來重構,速度會好很多。對于新手,或者前端不是太理解的人來說,做爬蟲還是比較坑的,我的經驗來說,做爬蟲最好還是要懂點前端, 當然懂得越多越好,爬蟲與前端的反爬蟲一直是這樣相愛相殺,所以你越了解你的敵人,你就越得心就手。main.py # 主程序url_manager.py # url管理器html_downloader.py # 下載器 相當于scrapy的downloaderhtml_parser.py # 網頁解析器 scrapy的解析直接就是在spiders里html_outputer.py # 數(shù)據(jù)處理器 相當于scrapy的item pipeline
有了這幾個類,我們已經可以完成一個簡單的框架了。main.py
里主要是保證任務的進行。import url_managerimport html_downloaderimport html_outputerimport html_parserclass SpiderMain(object): def __init__(self): self.urls = url_manager.UrlManager() self.downloader = html_downloader.HtmlDownloader() self.parser = html_parser.HtmlParser() self.outputer = html_outputer.HtmlOutputer() def craw(self, key_word, page_num): count = 1 self.urls.build_url(key_word, int(page_num)) while self.urls.has_new_url(): try: new_url = self.urls.get_new_url() print(f"craw {count} : {new_url}") html_cont = self.downloader.download(new_url) new_data = self.parser.parse(new_url, html_cont) self.outputer.collect_data(new_data) count += 1 except Exception as e: print("craw failed", e) self.outputer.to_csv() # return self.outputer.datasif __name__ == "__main__": spider = SpiderMain() print(spider.craw("women dress", "2"))
主程序內容比較簡單,導入相應的類,構建了一個爬蟲主類,傳入關鍵詞和頁數(shù),爬蟲就愉快的開始爬網了。 核心就在這個craw
函數(shù)。 1. 首先url管理器構建一個初始url,告訴爬蟲從哪兒開始爬取。 2. 然后爬蟲開始看url管理器里有沒有新的url,有就獲取新的url,把新的url傳入下載器進行下載。 3. 然后下載器把下載的數(shù)據(jù)傳入解析器進行解析。 4. 數(shù)據(jù)處理器收集解析器解析出來的新數(shù)據(jù)。 5. 數(shù)據(jù)處理器保存數(shù)據(jù)到本地。url_manage.py
url管理器build_url
構建初始網址 add_new_url
添加新的url到管理器 has_new_url
檢查管理器里有沒有新的url get_new_url
從管理器里獲取新的url show_urls
遍歷管理器里的url 這里的功能實際上都是針對的__init__
里面設置的兩個set
,這里沒有使用數(shù)據(jù)庫,使用數(shù)據(jù)庫也是一樣的效果。def __init__(self): self.new_urls = set() self.old_urls = set() self.site = 'http://www.dhgate.com/w/{0}/{1}.html'
html_downloader.py
下載器requests
包,使用其相關方法就完成了download
方法。html_parser.py
網頁解析器def _get_new_data(self, page_url, soup): items = soup.find_all("div", "listitem") datas = [] for item in items: title = item.find("h3").find("a").text # 標題 product_url = HtmlParser.format_str( item.select("h3 > a.subject")[0].get("href")) price = item.find("li", "price").text # 價格 min_price, max_price = re.findall(r'(/d+/.*/d+)', price) # 最低價,最高價 attribute = item.find("ul", "attribute").text min_order = re.findall(r'Min. Order: (/d+)', attribute)[0] # 起訂量 order = re.findall(r'Sold: (/d+)', attribute) order = order[0] if len(order) > 0 else 0 # 訂單量 feedback = item.find("span", "reviewnum") feedback = re.findall(r"/d+", feedback.text)[0] if feedback else 0 # 產品好評 seller = list(item.find("span", "seller").stripped_strings)[-1] # 賣家 store_url = item.find("span", "seller").find("a")['href'] # 店鋪鏈接 store_feedback = item.find("li", "feedback") store_feedback = re.findall( r"/d+/.*/d+", store_feedback.text)[0] if store_feedback else 0 # 店鋪評價 data = { 'page_url': page_url, 'title': title, 'product_url': 'http:' + product_url, 'min_price': min_price, 'max_price': max_price, 'min_order': min_order, 'order': order, 'feedback': feedback, 'seller': seller, 'store_url': store_url, 'store_feedback': store_feedback } datas.append(data) return datas
就不多說了,parse
方法里引用_get_new_data
解析完成返回數(shù)據(jù)。html_outputer.py
數(shù)據(jù)處理器collect_data
收集前面處理好的數(shù)據(jù) to_html
把數(shù)據(jù)輸出成html格式 to_csv
把數(shù)據(jù)輸出成csv格式,這個就和我們之前做的一樣,不過這里使用了csv
包,效率更高def to_html(self): with open('output.html', 'w') as f: f.write("<html>") f.write("<body>") f.write("<table>") f.write("<tr>") for key in self.datas[0].keys(): f.write(f"<td>{key}</td>") f.write("</tr>") for data in self.datas: f.write("<tr>") for key, value in data.items(): f.write(f"<td>{value}</td>") f.write("</tr>") f.write("</table>") f.write("</body>") f.write("</html>") def to_csv(self, path="output.csv"): with open(path, 'w', newline="") as f: try: writer = csv.DictWriter(f, self.datas[0].keys()) except IndexError: print(self.datas[0].keys()) writer.writeheader() for data in self.datas: writer.writerow(data)
可以看到輸出到html稍微麻煩點,主要是要寫html
特有的標簽,而csv就相當簡單了,csv
包里有相應的方法,可以直接使用。tk
來實現(xiàn)一個界面,方便普通用法使用。大家記得關注我公眾號,想要 源碼可以在公眾號后臺輸入 0020 獲取。目標:致力于幫助中國企業(yè)出海淘金
使命:為國內企業(yè)跨境出海提供動力支持
愿景:打造用戶期待和尊重的外貿服務商
頂部
合作
微信
公眾號