年初自學python一段時間,項目中很少遇到需要實踐python的地方,最近公司機頂盒的應用市場需要進行應用掛網,測試同事需要從當貝市場和奇珀市場下載特定的200多個應用,並提取信息掛到自己的服務器上,作爲客戶端開發的我,能用程序實現的絕對不會使用重複勞動力。
安裝python 3.7,針對爬蟲程序依賴的module,以管理員身份啓動cmd
所需模塊:beautifulsoup4 處理網頁解析
requests 處理網頁請求
re 處理正則表達式
lxml 是python的一個解析庫,支持HTML和XML的解析
lxml需要自己下載:https://www.lfd.uci.edu/~gohlke/pythonlibs/
使用pip install <模塊>即可。
如下圖,需要抓取應用名稱,版本,簡介和圖片並下載。
chrome F12後可以看到相應標籤的class等屬性,右鍵-copy-copy selector就可以複製css選擇器標籤元素。
關鍵代碼如下:
def downloadApp(AppName):
url = 'http://www.dangbei.com/app/plus/search.php?kwtype=0&q=' + AppName
# 獲取網頁源碼
web_data = requests.get(url, headers=headers)
# print('content:' + web_data.text)
# 解析網頁
soup = BeautifulSoup(web_data.text, 'lxml')
try:
# 獲取第一個搜索內容的名字
firstRecordName = soup.select('#softList > li:nth-of-type(1) > div > div.softInfo > p.title > a')[
0].get_text().strip()
if AppName in firstRecordName:
# 正則表達式找出擡頭與紅色關鍵詞之間的跳轉鏈接文本
# 正則表達式的運用可以參考這篇博客: https://www.cnblogs.com/chuxiuhong/p/5885073.html
pattern0 = re.compile(r'<a href=".+' + "<font color='red'>")
linkUrls = pattern0.findall(web_data.text)
# print(linkUrls[0])
# 獲取二級頁面鏈接 http://www.dangbei.com/app/tv/2015/0723/2687.html變爲https://m.dangbei.com/wap-view-2687.html
tempStr = linkUrls[0].split()[1].split('"')[1]
tempList = re.findall(r'\d+', tempStr)
linkUrl = 'https://m.dangbei.com/wap-view-' + tempList[2] + ".html"
print("'" + firstRecordName + "'" + "的應用頁面:" + linkUrl)
# 進入二級頁面,以獲取應用詳情
web_data = requests.get(linkUrl, headers=headers)
soup = BeautifulSoup(web_data.text, 'lxml')
try:
version = soup.select('div.app-cat > span:nth-of-type(4)')[0].get_text().strip()
version = version.split(':')[1]
print("'" + firstRecordName + "'" + "的版本號:\n" + version)
filename = AppName + '_' + version
appdir = os.path.join(PATH, filename)
isExists = os.path.exists(appdir)
if not isExists:
# 創建文件夾
print('新建了一個', filename, '的文件夾!')
os.makedirs(appdir)
# 切換工作路徑到AppName下
os.chdir(appdir)
else:
print(filename, '文件夾已經存在了!')
# if shutil.rmtree(appdir, True):
# os.rmdir(appdir) # 只能刪除空目錄,否則報錯
os.chdir(appdir)
return
introduction = soup.select('div.info-content > div > p')[0].get_text()
print("'" + firstRecordName + "'" + "的詳情介紹:\n" + introduction)
# 'w'或者'wb'表示寫文本文件或寫二進制文件
with open(filename + '.txt', 'w', encoding='utf-8') as f:
f.write(introduction)
photourl = soup.select('div.scroll_box > ul > li')
print("'" + firstRecordName + "'" + "的圖片地址:")
count = 1
for temp in photourl:
temp_url = temp.find('img')['src']
temp_url = 'http://' + temp_url.split('//')[1]
large_url = temp_url.split('!')[0]
print(large_url)
urllib.request.urlretrieve(large_url, 'large_%s.jpg' % count)
urllib.request.urlretrieve(temp_url, 'small_%s.jpg' % count)
count += 1
apk = soup.select('div.info_downxload > a.btn_download_app')[0]
apkurl = apk.attrs['href']
apktitle = apk.attrs['title']
print("'" + firstRecordName + "'" + "的下載鏈接:\n" + apkurl)
urllib.request.urlretrieve(apkurl, apktitle + '_' + version + '.apk')
except:
print('search error')
os.chdir(PATH)
with open('record.txt', 'a+', encoding='utf-8') as f:
f.write(AppName + '\n')
else:
print("未找到與'" + AppName + "'相關的內容")
os.chdir(PATH)
with open('record.txt', 'a+', encoding='utf-8') as f:
f.write(AppName + '\n')
except:
print("未找到與'" + AppName + "'相關的內容")
os.chdir(PATH)
with open('record.txt', 'a+', encoding='utf-8') as f:
f.write(AppName + '\n')
抓取結果如圖:
大致使用:applist.txt輸入需要抓取的應用名稱,若有搜索結果便新建一個應用文件夾,裏面存放圖片和apk等信息,由於抓取的信息需要存放在對應目錄,採用線程池並行下載會存在文件存放錯亂的問題,所以採用串行下載。
期間遇到的問題:
- 複製的selector的若包含nth-child,得到的結果是空,使用nth-of-type即可。兩者區別: nth-of-type(n) 匹配屬於父元素的特定類型的第 N 個子元素的每個元素,nth-child(n)選取父元素的第 N 個子元素,與類型無關。
- os.rmdir只能刪除空目錄,否則報錯;shutil.rmtree() 可遞歸刪除文件夾下的所有子文件夾和子文件。
- 讀寫文件,記得統一編碼,比如encoding=‘utf-8’。