Day10回顧
分布式爬蟲原理及實現(xiàn)
# 原理
多臺主機共享1個爬取隊列
# 實現(xiàn)
scrapy_redis
分布式爬蟲配置
1、完成非分布式scrapy爬蟲項目
2僵井、settings.py中指向新的調(diào)度器退疫、去重機制及redis服務(wù)器IP地址及端口號
3秸妥、設(shè)置管道 - MySQL吊圾、MongoDB或Redis
redis_key分布式爬蟲配置
1挥等、完成非分布式scrapy爬蟲項目 - 不能重寫 start_requests()
2、settings.py中指向新的調(diào)度器抛腕、去重機制及redis服務(wù)器的IP地址及端口號
3芋绸、設(shè)置管道 - MySQL、MongoDB或Redis
4担敌、爬蟲文件使用RedisSpider類
1摔敛、去掉start_urls
2、添加redis_key : redis_key = "name:spider"
5全封、部署到多臺服務(wù)器
6马昙、連接redis,執(zhí)行 LPUSH name:spider First_URL
機器視覺
1售貌、OCR
2给猾、tesseract-ocr
3疫萤、pytesseract
Fiddler+Browser配置
1颂跨、Fiddler端 - 安裝根證書、只抓瀏覽器扯饶、設(shè)置端口
2恒削、Browser端 - 安裝代理插件(SwithyOmega)并創(chuàng)建切換新代理
Fiddler+Phone配置
1、Fiddler端 - 安裝根證書尾序、抓所有進程钓丰、設(shè)置端口、允許遠程
2每币、Phone端 - 修改網(wǎng)絡(luò)携丁、下載并安裝證書
爬蟲總結(jié)
# 1、什么是爬蟲
爬蟲是請求網(wǎng)站并提取數(shù)據(jù)的自動化程序
# 2、robots協(xié)議是什么
爬蟲協(xié)議或機器人協(xié)議,網(wǎng)站通過robots協(xié)議告訴搜索引擎哪些頁面可以抓取梦鉴,哪些頁面不能抓取
# 3李茫、爬蟲的基本流程
1、請求得到響應(yīng)
2肥橙、解析
3魄宏、保存數(shù)據(jù)
# 4、請求
1存筏、urllib
2宠互、requests
3、scrapy
# 5椭坚、解析
1予跌、re正則表達式
2、lxml+xpath解析
3善茎、json解析模塊
4匕得、BeautifulSoup解析模塊
# sudo pip3 install beautifulsoup4
# from bs4 import BeautifulSoup
# 6、selenium+browser
# 電腦端反爬特別嚴重時巾表,可以對應(yīng)手機app中嘗試
# 7汁掠、常見反爬策略
1、Headers : 最基本的反爬手段集币,一般被關(guān)注的變量是UserAgent和Referer考阱,可以考慮使用瀏覽器中
2、UA : 建立User-Agent池,每次訪問頁面隨機切換
3鞠苟、拉黑高頻訪問IP
數(shù)據(jù)量大用代理IP池偽裝成多個訪問者,也可控制爬取速度
4乞榨、Cookies
建立有效的cookie池,每次訪問隨機切換
5当娱、驗證碼
驗證碼數(shù)量較少可人工填寫
圖形驗證碼可使用tesseract識別
其他情況只能在線打碼吃既、人工打碼和訓練機器學習模型
6、動態(tài)生成
一般由js動態(tài)生成的數(shù)據(jù)都是向特定的地址發(fā)get請求得到的跨细,返回的一般是json
7鹦倚、簽名及js加密
一般為本地JS加密,查找本地JS文件,分析,或者使用execjs模塊執(zhí)行JS
8、js調(diào)整頁面結(jié)構(gòu)
9冀惭、js在響應(yīng)中指向新的地址
# 8震叙、scrapy框架的運行機制
# 9、分布式爬蟲的原理
多臺主機共享一個爬取隊列
Day11筆記
移動端app數(shù)據(jù)抓取 - 瀏覽器F12
有道翻譯手機版破解案例
import requests
from lxml import etree
word = input('請輸入要翻譯的單詞:')
url = 'http://m.youdao.com/translate'
data = {
'inputtext': word,
'type': 'AUTO',
}
html = requests.post(url,data=data).text
parse_html = etree.HTML(html)
result = parse_html.xpath('//ul[@id="translateResult"]/li/text()')[0]
print(result)
途牛旅游
目標
完成途牛旅游爬取系統(tǒng)散休,輸入出發(fā)地媒楼、目的地,輸入時間戚丸,抓取熱門景點信息及相關(guān)評論
地址
1划址、地址: http://www.tuniu.com/
2、熱門 - 搜索
3、選擇: 相關(guān)目的地夺颤、出發(fā)城市对人、出游時間(出發(fā)時間和結(jié)束時間)點擊確定
4、示例地址如下:
http://s.tuniu.com/search_complex/whole-sh-0-%E7%83%AD%E9%97%A8/list-a{觸發(fā)時間}_{結(jié)束時間}-{出發(fā)城市}-{相關(guān)目的地}/
項目實現(xiàn)
- 1拂共、創(chuàng)建項目
scrapy startproject Tuniu
cd Tuniu
scrapy genspider tuniu tuniu.com
- 2牺弄、定義要抓取的數(shù)據(jù)結(jié)構(gòu) - items.py
# 一級頁面
# 標題 + 鏈接 + 價格 + 滿意度 + 出游人數(shù) + 點評人數(shù) + 推薦景點 + 供應(yīng)商
title = scrapy.Field()
link = scrapy.Field()
price = scrapy.Field()
satisfaction = scrapy.Field()
travelNum = scrapy.Field()
reviewNum = scrapy.Field()
recommended = scrapy.Field()
supplier = scrapy.Field()
# 二級頁面
# 優(yōu)惠券 + 產(chǎn)品評論
coupons = scrapy.Field()
cp_comments = scrapy.Field()
-
3、爬蟲文件數(shù)據(jù)分析與提取
頁面地址分析
http://s.tuniu.com/search_complex/whole-sh-0-熱門/list-a20190828_20190930-l200-m3922/ # 分析 list-a{出發(fā)時間_結(jié)束時間-出發(fā)城市-相關(guān)目的地}/ # 如何解決宜狐? 提取 出發(fā)城市及目的地城市的字典,key為城市名稱,value為其對應(yīng)的編碼 # 提取字典势告,定義config.py存放
代碼實現(xiàn)
# -*- coding: utf-8 -*- import scrapy from ..config import * from ..items import TuniuItem import json class TuniuSpider(scrapy.Spider): name = 'tuniu' allowed_domains = ['tuniu.com'] def start_requests(self): s_city = input('出發(fā)城市:') d_city = input('相關(guān)目的地:') start_time = input('出發(fā)時間(20190828):') end_time = input('結(jié)束時間(例如20190830):') s_city = src_citys[s_city] d_city = dst_citys[d_city] url = 'http://s.tuniu.com/search_complex/whole-sh-0-%E7%83%AD%E9%97%A8/list-a{}_{}-{}-{}'.format(start_time,end_time,s_city, d_city) yield scrapy.Request(url, callback=self.parse) def parse(self, response): # 提取所有景點的li節(jié)點信息列表 items = response.xpath('//ul[@class="thebox clearfix"]/li') for item in items: # 此處是否應(yīng)該在for循環(huán)內(nèi)創(chuàng)建? tuniuItem = TuniuItem() # 景點標題 + 鏈接 + 價格 tuniuItem['title'] = item.xpath('.//span[@class="main-tit"]/@name').get() tuniuItem['link'] = 'http:' + item.xpath('./div/a/@href').get() tuniuItem['price'] = int(item.xpath('.//div[@class="tnPrice"]/em/text()').get()) # 判斷是否為新產(chǎn)品 isnews = item.xpath('.//div[@class="new-pro"]').extract() if not len(isnews): # 滿意度 + 出游人數(shù) + 點評人數(shù) tuniuItem['satisfaction'] = item.xpath('.//div[@class="comment-satNum"]//i/text()').get() tuniuItem['travelNum'] = item.xpath('.//p[@class="person-num"]/i/text()').get() tuniuItem['reviewNum'] = item.xpath('.//p[@class="person-comment"]/i/text()').get() else: tuniuItem['satisfaction'] = '新產(chǎn)品' tuniuItem['travelNum'] = '新產(chǎn)品' tuniuItem['reviewNum'] = '新產(chǎn)品' # 包含景點+供應(yīng)商 tuniuItem['recommended'] = item.xpath('.//span[@class="overview-scenery"]/text()').extract() tuniuItem['supplier'] = item.xpath('.//span[@class="brand"]/span/text()').extract() yield scrapy.Request(tuniuItem['link'], callback=self.item_info, meta={'item': tuniuItem}) # 解析二級頁面 def item_info(self, response): tuniuItem = response.meta['item'] # 優(yōu)惠信息 coupons = ','.join(response.xpath('//div[@class="detail-favor-coupon-desc"]/@title').extract()) tuniuItem['coupons'] = coupons # 想辦法獲取評論的地址 # 產(chǎn)品點評 + 酒店點評 + 景點點評 productId = response.url.split('/')[-1] # 產(chǎn)品點評 cpdp_url = 'http://www.tuniu.com/papi/tour/comment/product?productId={}'.format(productId) yield scrapy.Request(cpdp_url, callback=self.cpdp_func, meta={'item': tuniuItem}) # 解析產(chǎn)品點評 def cpdp_func(self, response): tuniuItem = response.meta['item'] html = json.loads(response.text) comment = {} for s in html['data']['list']: comment[s['realName']] = s['content'] tuniuItem['cp_comments'] = comment yield tuniuItem
-
4抚恒、管道文件處理 - pipelines.py
print(dict(item))
5咱台、設(shè)置settings.py
出發(fā)城市和目的地城市的編號如何獲取俭驮?- tools.py
# 出發(fā)城市
# 基準xpath表達式
//*//*[@id="niuren_list"]/div[2]/div[1]/div[2]/div[1]/div/div[1]/dl/dd/ul/li[contains(@class,"filter_input")]/a
name : ./text()
code : ./@href [0].split('/')[-1].split('-')[-1]
# 目的地城市
# 基準xpath表達式
//*[@id="niuren_list"]/div[2]/div[1]/div[2]/div[1]/div/div[3]/dl/dd/ul/li[contains(@class,"filter_input")]/a
name : ./text()
code : ./@href [0].split('/')[-1].split('-')[-1]
? 代碼實現(xiàn)
import requests
from lxml import etree
url = 'http://s.tuniu.com/search_complex/whole-sh-0-%E7%83%AD%E9%97%A8/'
headers = {'User-Agent':'Mozilla/5.0'}
html = requests.get(url,headers=headers).text
parse_html = etree.HTML(html)
# 獲取出發(fā)地字典
# 基準xpath
li_list = parse_html.xpath('//*[@id="niuren_list"]/div[2]/div[1]/div[2]/div[1]/div/div[3]/dl/dd/ul/li[contains(@class,"filter_input")]/a')
src_citys = {}
dst_citys = {}
for li in li_list:
city_name_list = li.xpath('./text()')
city_code_list = li.xpath('./@href')
if city_name_list and city_code_list:
city_name = city_name_list[0].strip()
city_code = city_code_list[0].split('/')[-1].split('-')[-1]
src_citys[city_name] = city_code
print(src_citys)
# 獲取目的地字典
li_list = parse_html.xpath('//*[@id="niuren_list"]/div[2]/div[1]/div[2]/div[1]/div/div[1]/dl/dd/ul/li[contains(@class,"filter_input")]/a')
for li in li_list:
city_name_list = li.xpath('./text()')
city_code_list = li.xpath('./@href')
if city_name_list and city_code_list:
city_name = city_name_list[0].strip()
city_code = city_code_list[0].split('/')[-1].split('-')[-1]
dst_citys[city_name] = city_code
print(dst_citys)