數據獲取途徑
注意:robots.txt
1、瀏覽器版Chrome
2、手機版Chrome
3、合作網站(豬隊友網站)、子網站
請求方式
requests.get(url,headers = headers,verify=False,proxies = proxies);
requests.post(url,data=data,headers = headers,verify=False,proxies = proxies)
Requests: (第三方庫)
Response = requests.get(url,headers = headers)
Response = requests.post(url,data=data,headers = headers)
Response: (requests生成的實例對象)
Response.text 獲取str 數據
Response.content 獲取byte 數據 可以使用.decode()解碼
Response.status_code 獲取返回狀態碼(狀態碼200不一定代表數據獲取成功,僅代表請求成功)
Response.request.headers 獲取請求頭內容。
Response.headers 查看請求的數據類型,(可以看到是json格式,utf-8編碼)
Proxies: 使用代理
Response = requests.get(url,headers = headers,proxies = proxies)
Prioxies形式:字典
Proxies = {
“http”:”http://123.123.123”,
“http”:”http://456.123.555”.
“http”:”http://123.977.123”.
................
}
處理cookies、session請求:
使用方法:
1、實例化一個session對象
2、讓session發送get或者post請求
Session =requests.session()
Response = session.get(url,headers)
如果需要攜帶cookie訪問網站,需要獲取cookie。
三種方式:
1、需要登錄,藉助session進行第一次訪問將cookie寫入。獲取cookie
2、其他途徑獲取大量cookie,直接將cookie寫入請求data={}字典中
3、Get請求獲取cookie並寫入請求data中。
反爬機制
通常防止爬蟲被反主要有以下幾個策略:
1、動態設置User-Agent(隨機切換User-Agent,模擬不同用戶的瀏覽器信息)
2、禁用Cookies(也就是不啓用cookies middleware,不向Server發送cookies,有些網站通過cookie的使用發現爬蟲行爲)
3、可以通過COOKIES_ENABLED 控制 CookiesMiddleware 開啓或關閉
4、Google Cache 和 Baidu Cache:如果可能的話,使用谷歌/百度等搜索引擎服務器頁面緩存獲取頁面數據。
5、使用IP地址池:VPN和代理IP,現在大部分網站都是根據IP來ban的。
6、使用 Crawlera(專用於爬蟲的代理組件),正確配置和設置下載中間件後,項目所有的request都是通過crawlera發出。
7、設置延遲下載(防止訪問過於頻繁,設置爲 2秒 或更高)
DOWNLOADER_MIDDLEWARES = {
'scrapy_crawlera.CrawleraMiddleware': 600
}
CRAWLERA_ENABLED = True
CRAWLERA_USER = '註冊/購買的UserKey'
CRAWLERA_PASS = '註冊/購買的Password'
使用代理前,先檢查代理ip可不可用。
使用requests模塊檢查ip可用不可用,如果ip地址存放在redis中。使用程序不挺讀取ip地址,發起請求。判斷ip地址是否可用。如果不可用直接刪掉。在使用scrapy獲取Ip時,大部分都是可用的。
如果購買代理,需要使用到賬號密碼,使用bas64加密。參考html課件。
Url
建議:
如果url請求路徑有很多,無法確定真實的請求url路徑,可以嘗試提交內容的改變,查看請求路徑中不變的Url. 參考可能需要的參數是否包含在From date中。增加判斷真確的機率。
1、from表單中的action=”www.xxx.com”可以獲得
Key、value是充from表單中的input標籤中獲取。
<input name=”email”>
<input name=”password”>
2、通過瀏覽器中Network中抓包
1. 通過輸入錯誤密碼,獲得請求路徑
2. 通過Chrome中勾選Preserve log功能,防止頁面跳轉找不到url,獲取請求路徑Name信息。
備註:
通過pyquery的history屬性,發現baidu這些連接大多進行了redirect(http 302),但是有一部分鏈接是直接獲得了http200回覆。對於從百度爬取的加密的url,進行requests.get()時不允許跳轉(allow_redirects=False)。然後針對這兩類服務器回覆分別處理:
http 302跳轉:從headers中的'location'可以獲得原始url;
http 200回覆:從content中通過正則表達式獲取原始url
3、火狐瀏覽器中編輯請求頭:
網絡 → 消息頭 → 可以編輯請求頭(增加或刪除referer等請求頭)重發。
數據來源的獲取
一 、如果獲取的數據是寫死的,不改變的。可以直接拿來用,不需要了解作用,
二 、如果獲取的數據是動態變換的,需要研究其生成方式,比如js方法
三 、如果傳遞相同的數據,得到的數據每次都是不同的,可以判定使用了【加鹽】,需要了解生成方式,使用Python代碼完成相同邏輯。加密的兩種方式:服務器保存key、value,將鹽值發送瀏覽器,邏輯加密後返回key、value;第二種相反。
1、通過Chremo中的Search all files進行全局數據搜索。
2、代碼中打斷點,實現代碼的邏輯數據顯示。
3、定位想要的js:
3.1 觸發事件:通過Chremo選擇會觸發的js事件的【按鈕】,Elements中Event Listeners ,Framework listeners功能鎖定js代碼。
3.2 隱藏的傳輸事件:通過Chremo中Network中需要數據的Request URl 地址,通過路徑中的需要的參數(url關鍵字),尋找js代碼。全局搜索Search all files。
4、在Sourses來源中查看相應JS代碼。
5、將未知的功能粘貼至Console中,實現反轉。
相關軟件加載(淘寶NPM鏡像):http://npm.taobao.org
Url路徑拼接
url路徑解碼:
XPATH 重點
一 、 在chrome瀏覽器中的Elements中查看html進行調試,但是爬蟲獲取的是url對應的響應,往往不同於elements中的格式。(應從實際已請求的返回值進行篩選,因爲使用etree工具可能解析有誤,導致節點鎖定錯誤)需要從Network或者程序中使用etree.tostring打印修改後返回的html數據格式。
二 、 可以使用chremo中的xpath helper插件提供的Copy→Copy XPath功能,直接生成選中節點的路徑。
獲取文本
a/text() 獲取a下的文本
a//text() 獲取a下的所有標籤的文本
//a[text()='下一頁'] 選擇文本爲下一頁三個字的a標籤
@符號: 選取屬性
a/@href
//ul[@id="detail-list"]
/ 下一級(層)
// 下任何級(層)
在xpath最前面表示從當前html中任意位置開始選擇
li//a 表示的是li下任何一個標籤
li[2] li標籤第二個
li[last()-3] li標籤倒數第三個
ll[position()<4] li標籤前三個
| 或
//book/title | //book/price
1 、Contains 包含
//div[contains(@class, ”i” )] 表示所有div中包含class=”i”的標籤
2 、Not 不包含
特殊用法:
/book[price>35.00]/title 選取book元素中,price元素的值大於35.00的title元素
節點選擇法:
* 匹配任何元素節點
@* 匹配任何屬性節點
node() 匹配任何類型的節點
lxml能夠接受bytes和str的字符串
提取頁面數據的思路:
先分組,取到一個包含分組標籤的列表 (先取對象,生成對象列表)
遍歷,取其中每一組進行數據的的提取,不會造成數據的對應錯亂。 (遍歷對象列表,針對每一層對象單獨寫獲取方式。配合三元表達式完成邏輯判斷)
Xpath的更多語法:https://msdn.microsoft.com/zh-cn/library/ms256039(v=vs.80).aspx
Queue隊列
進程會等所有的線程結束後再結束
設置守護線程,把當前的線程作爲一個從屬的線程,依賴於另外一個線程,另外一個線程結束,當前線程就結束。
1、Queue.emty 判斷當前隊列是都是空的,如果是回覆True
2、Queue.full 判斷是都滿
3、Queue.get 從池中取數據
4、Queue.get_nowait 取數據,取不到就報錯
5、Queue.task_done() 對任務進行計數
6、Queue.put 推數據到池子中
7、Queue.put_nowait 推數據到池子,不成功報錯
8、Queue.qsize 獲取隊列保存個數。
9、Queue.join 讓主線程堵塞(讓主線程等待隊列的任務數),等待子線程結束後主線程結束(python3中)
10、Thread.setDaemon(Ture) 讓該線程變成守護線程(該線程不重要,主線程結束,該線程結束)
11、
12、
注意:Queue.put 計數+1 ,Queue.get和Queue.task_done一起使用 計數-1
動態請求HTML(優化請求)
1 、 儘量減少請求次數(減少反扒機率)
能抓列表頁,不抓詳情頁。
保存獲取到的html頁面,供插錯和重複請求使用
2 、 關注網站的所有類型的頁面(爬取難度:極速版頁面,手機版頁面,電腦版頁面)
Wap頁面,觸屏版頁面
H5頁面
APP
3 、 多僞裝(防止被反爬)
動態UA(headers={“User-Agent”:“http://.....”,。。。。}})
代理ip
不使用cookie
4 、 利用多線程分佈式
在不被ban的請求下儘可能的提高速度
Selenium 和 PhantomJS
Selenium是 Web的自動化測試工具。 (效率比較低,訪問頁面需要加載完才能進行數據的獲取,速度慢。) 可以直接運行在瀏覽器上,支持所有主流瀏覽器(包括PhantomJS無邊界瀏覽器),可以接收命令,讓瀏覽器自動加載頁面,獲取需要的數據,甚至頁面截屏。
driver = webdriver.Chrome() # 實例化一個瀏覽器 (Chrome需要安裝)
driver.get(‘http://www.baidu.com’) # 發送請求
time.sleep(3) # 睡3秒
driver.quit() # 退出瀏覽器
driver.get_cookies() # 獲取cookies 列表
列表推導式: cookies = {i["name"]:i["value"] for i in cookies_list}
driver.page_source # 瀏覽器中elements的內容,瀏覽器所有內容加載完畢後的html字符串
driver.current_url # 頁面加載/跳轉完成後的url地址。
driver.close() # 退出當前頁面
元素定位的方法:
find_element_by_id (根據id返回一個)
find_elements_by_xpath (返回列表,如果路徑寫錯,獲取不到返回空列表 [] )
find_elements_by_link_text (根據連接的文本選擇)
find_elements_by_partial_link_text (根據連接的部分文本選擇)
find_elements_by_tag_name (根據標籤選擇)
find_elements_by_class_name (根據class選擇)
find_elements_by_css_selector (根據CSS選擇)
獲取文本和獲取屬性
先定位到元素,然後調用.text或者get_attribute方法來去
selenium獲取的頁面數據是瀏覽器中elements的內容
findelement和findelements的區別
find_element返回一個element,如果沒有會報錯
find_elements返回一個列表,沒有就是空列表
在判斷是否有下一頁的時候,使用find_elements來根據結果的列表長度來判斷
如果頁面中含有iframe、frame,需要先調用driver.switch_to.frame的方法切換到frame中才能定位元素
<iframe id = “aaa” name = “bbb” ..............>
driver.switch_to.frame(“aaa”)
或driver.switch_to.frame(“bbb”)
或driver.switch_to.frame(Selenium選擇的元素)
細節重點:
selenium請求第一頁的時候回等待頁面加載完了之後在獲取數據,但是在點擊翻頁之後,hi直接獲取數據,此時可能會報錯,因爲數據還沒有加載出來,需要time.sleep(3)
selenium中find_elements_by_class_name智能接收一個class對應的一個值,不能傳入多個
driver.find_element_by_id(“kw”).send_key(“python”) # 選中input框,輸入內容“python”
driver.find_element_by_id(“su”).click() # 選中input框,執行點擊事件。
PhantomJS 是 無界面(headless)瀏覽器 , 它將網站加載到內存並執行頁面JavaScript。
driver = webdriver.PhantomJS() # 實例化內存瀏覽器 (PhantomJS需要安裝)
driver.set_window_size() # 設置截屏大小 如(1980,1080)
driver.maximize_window() # 最大化窗口
driver.save_screenshot(“./name.png”) 保存截屏圖片位置、類型
Cookie相關用法
{cookie[‘name’]:cookie[‘value’] for cookie in driver.get_cookies()} 列表推導式
driver.delete_cookie(“CookieName”) 刪除cookie
driver.delete_all_cookies()
應用場景:
1、cookie過期時間很長,常見於一些不規範的網站
2、能在cookie過期之前把搜有的數據拿到
3、配合其他程序使用,比如其使用selenium把登陸之後的cookie獲取到保存到本地,scrapy發送請求之前先讀取本地cookie
注意:
1、在scrapy框架中,setting中默認cookis在下一次請求中默認攜帶的。如果第一次請求中獲得,或者攜帶cookie後面的請求就會攜帶從傳遞。
2、Scrapy中攜帶cookies請求不能寫到headers中。原生的requests模塊可以將cookies寫到headers中。
驗證碼
1、驗證碼的識別
url不變,驗證碼不變
2、請求驗證碼的地址,獲得相應,識別
url不變,驗證碼會變
使用Selenium工具。
使用截圖工具PIL 模塊,可以實現截圖。注意,需要將瀏覽器寬高固定,要不然截圖位置無法定位。
思路:對方服務器返回驗證碼的時候,會和每個用戶的信息和驗證碼進行一個對應,之後,在用戶發送post請求的時候,會對比post請求中法的驗證碼和當前用戶真正的存儲在服務器端的驗證碼是否相同
驗證碼的獲取需要當前用戶的cookie,所以需要session發驗證碼請求,寫入session中一個cookie;
如果使用requests發送請求,需要攜帶cookie值,並將cookie值在不同的請求間傳遞使用。
1. 實例化session
2.使用seesion請求登錄頁面,獲取驗證碼的地址
3.使用session請求驗證碼,識別
4.使用session發送post請求’
使用selenium登錄,遇到驗證碼
url不變,驗證碼不變,同上
url不變,驗證碼會變
1.selenium請求登錄頁面,同時拿到驗證碼的地址
2.獲取登錄頁面中driver中的cookie,交給requests模塊發送驗證碼的請求,識別
3.輸入驗證碼,點擊登錄
雲打碼平臺:http://www.yundama.com/l
賬號:183************
密碼:******
下載相關運行包:
# 用戶名
username = '183********'
# 密碼
password = '**********'
# appid
appid = 4283
# appkey
appkey = '02074c64f0d0bb9efb2df455537b01c3'
# 驗證碼類型
# 驗證碼題分價格:http://www.yundama.com/price.html 寫codetype前先看下攻關網站的驗證碼是那種類型的,對比響應類型填寫。
codetype = 3007
# 超時
timeout = 60
注意點:
1、獲取html中的標籤路徑時,elements中的<tbody>標籤並不存在。
2、可以使用 切片 [1:-1]來過濾獲取的list。
3、From表單提交中,完整內容應該包還有:
用戶名、密碼
csrf_token
action method post enctype=application/www-x-urlencoded
authenticity_token
數據的格式整理
1、通過Chremo瀏覽器中Sources中的{} :Pretty print功能實現格式的轉換
2、Chremo中安裝JSONView插件。
3、網頁在線
4、Pychem
5、電腦安裝Atom
1、json.dumps ; json.loads ; json.dump ; json.load ; str() ; eavl() 用法區別:
json.dumps()
Python數據類型 → json字符串
將dict類型的數據轉成str
json.loads()
json字符串 → Python數據類型
json.loads()用於將str類型的數據轉成dict。
注:具有read()或者write()方法的對象就是類文件對象
f=open(“a.txt”,”r”) f就是類文件對象
json.dump()
python數據類型 → 包含json的類文件對象
json.dump()用於將dict類型的數據轉成str,並寫入到json文件中。
json.load()
包含json的類文件對象 → python數據類型
json.load()用於從json文件中讀取數據。
Str()
雖然可以轉換爲字符串,但是在write寫入過程中,沒有json.dumps靈活,例如:f.write(json.dumps(data,ensure_ascii=False,indent=2))可以攜帶格式參數。
Eavl()
處理不了層級太多的代碼,容易出錯。
2、lxml庫
lxml可以自動修正/補全html代碼(如果傳遞的數據標籤有缺失/不規範,可能導致修正後格式有誤。)
利用etree.HTML 將字符串(str/byte類型)轉化爲Element對象
Element對象具有xpath的方法
from lxml import etree
html = etree.HTML(text) # todo 返回的是html對象
etree.tostring( html ) # todo 獲取element對象中包含的byte類型的字符串
html.xpath(“語句”) # todo 獲取的是個列表集合(根據獲取路徑可以是:對象、herf屬性/text文本)
3、Print( etree.tostring(html對象).decode() )
查看通過etree修正後的html格式。
Scrapy shell交互終端
我們可以在未啓動spider的情況下嘗試及調試代碼,也可以用來測試XPath表達式
使用方法:
1、進入ipython/python交互終端
2、scrapy shell http://www.itcast.cn/channel/teacher.shtml
response.url:當前響應的url地址
response.request.url:當前響應對應的請求的url地址
response.headers:響應頭
response.body:響應體,也就是html代碼,默認是byte類型
response.requests.headers:當前響應的請求頭
注意:response.headers會採用默認的請求頭,所以需要先設置User-Agent:
3、自動拼接不完整的url路徑:urljoin()
import urllib
a = “aaa/aaa/aa/aaa/aa/aaa/ccc/ccc/cc/c/cccc”
b = “bbb/bbbb/bbbb/bbbb/bbb”
urllib.parse.urljoin(a,b)
→”aaaa/aaa/aaa/aaa/bbb/bbb/bbb/bbb/bbb/bbb”
數據的清洗
1、Response =requests.get(“http://www.baidu.com”)
Get請求獲取響應
2、response.cookies
返回值中可以提取cookies
3、requests.utils.dict_from_cookiejar(response.cookies)
Cookie轉字典
4、Requests.utils.cookiejar_from_dict({“key”:”value”})
字典轉換cookie
5、url地址解碼:
Requests.utils.unquote(“http%2f%2f..............”)
→“http://...............”
6、url地址編碼:
Repuest.utils.quote(“http://........”)
→”%ad123%232%sdfds.........”
7、SSLError:
SSL證書問題,可能存在安全隱患。(Https)
解決方法:添加verify=False response = requests.get(“http://www.baidu.com”, verify = False)
8、設置請求時間限制參數
timeout = 10 response = requests.get(url , timeout = 10)
9、Eval
eval() 能實現簡單的字符串和Python類型的轉換
10、Replace
把單引號替換爲雙引號
11、re.compile(編譯)
Compile將字符串按照傳入的正則方法,預先匹配一遍,當調用compile對象的方法時,提高效率。
注意:如果使用compile() , re.S需要放到compile(“.” , re.S)中
例如:
b = “asdasd123”
p = re.compile(“\d”)
p.findall(b)
→ [“1”,”2”,”3”]
12、match(從頭找一個)
13、findall(找所有)
Re.findall(“.” , “\n”, re.DOTALL)
在DOTALL模式中可以匹配換行符。re.DOTALL也可以寫成re.S
14、sub(替換)
re.sub(“\d”,”_”,b) 從b中匹配第一個條件”\d”,爲”_”。
15、遞歸函數:
16、列表推導式
content = [re.sub(r"\xa0|\s","",i) for i in content]
content = [i for i in content if len(i)>0] #去除列表中的空字符串
17、[ 0 : -1]
18、注意數據的覆蓋。Item結構(item的深拷貝)
Item如果設置的傳遞層數太多,再寫入數據庫中,會因爲底層的函數字段相同而覆蓋。所以傳遞item中,在適當節點需要使用硬拷貝deepcopy()函數。deepcopy(item)進行參數對象的傳遞,保證數據不會覆蓋。
19、隨機數random用法:
random.random()函數是這個模塊中最常用的方法了,它會生成一個隨機的浮點數,範圍是在0.0~1.0之間。
random.uniform()正好彌補了上面函數的不足,它可以設定浮點數的範圍,一個是上限,一個是下限。
random.randint()隨機生一個整數int類型,可以指定這個整數的範圍,同樣有上限和下限值,python random.randint。
random.choice()可以從任何序列,比如list列表中,選取一個隨機的元素返回,可以用於字符串、列表、元組等。
random.shuffle()如果你想將一個序列中的元素,隨機打亂的話可以用這個函數方法。
random.sample()可以從指定的序列中,隨機的截取指定長度的片斷,不作原地修改。
20、Url編碼/解碼:
當url地址含有中文或者“/”的時候,這是就需要用urlencode做以下編碼轉換:
urlencode的參數是詞典,它可以將key-value這樣的鍵值對轉換成我們想要的格式。
如果你用的是python2.*,urlencode在urllib.urlencode。
如果使用的是python3,urlencode在urllib.parse.urlencode
當urlencode之後的字符串傳遞過來之後,接受完畢就要解碼了——urldecode.urllib提供了unquote()這個函數
Requests.utils.unquote(aaa)
21、<noscript>在禁用js時,裏面的內容纔會顯示。
22、選擇式數據提取,排除空數據方式。
item["m_cate"] = dl.xpath("./dt//text()").extract()
item["m_cate"] = [i.strip() for i in item["m_cate"] if len(i.strip())>0][0]
23、去除空白字符
string.lstrip() 截掉 string 左邊(開始)的空白字符
string.rstrip() 截掉 string 右邊(末尾)的空白字符
string.strip() 截掉 string 左右兩邊的空白字符
數據導出
Mongoexport
數據的存儲
直接寫成文本:
With open(“name.txt”,”w”,encoding=”utf-8”) as f:
f.write(json.dumps(data,ensure_ascii=False,indent=2))
encoding=”utf-8” 設置打開方式
ensure_ascii=False 消除默認ascii碼。
indent=2 整理代碼格式,設置換行縮進2個字符。
數據庫
Mongodb
非關係型數據庫
查看數據庫 show dbs / show databases
查看當前數據庫 db
使用(創建)數據庫 use test (只有插入數據,創建的數據庫纔會顯示)
刪除當前數據庫 db.dropDatabase()
向不存在的集合中第一次加入數據,集合會被創建 db.createCollection(name,options)
給集合設置上限:db.createCollection(“sub”,{capped:true,size:10}) true 表示設置上限
查看集合:show collections
刪除集合:db.集合名稱.drop()
Object ID :文檔ID
String : 字符串,最常用,必須是有效的UTF-8
Boolean :存儲一個布爾值,true或fales
Integer : 整數可以是32位或64位,這取決於服務器
Double : 存儲浮點值
Arrays : 數組或列表,多個值存儲到一個鍵
Object : 用於嵌入式的文檔,即一個值爲一個文檔
Null : 存儲Null 值
Timestamp: 時間戳,表示從1970-1-1到現在的總秒數
Date: 存儲當前日期或時間的UNIX時間格式
創建時間 : new Date(‘2017-12-20’)
插入一條數據: db.nametest.insert({“name”:”xiaowang”,”age”:”18”})
objectID是一個12字節的16進制數:
前4個字節是時間戳
接下來3個字節的機器ID
接下來的2個字節中MongoDB的服務進程id
最後3個字節是簡單的增量值
更改數據: db.集合名稱.save(document)
如果文檔的_id已經存在則修改,如果文檔的_id不存在則添加
查詢 db.集合名稱.find()
更新 db.集合名稱.update(<query>,<update>,{multi:<boolean>})
參數query: 查詢條件
參數update: 更新操作符
參數multi: 可選,默認是false, 表示只更新找到到第一條記錄
值爲true 表示把滿足條件的文檔全部更新
替換一整條:db.stu.update({name:’hr’},{name:’mnc’})
更新對應項一條:db.stu.update({name:’hr’},{$set:{name:’hys’}})
更新全部:db.stu.update({},{$set:{gender:0}},{multi:true})
注意:”multi update only works with $ operators”
刪除:db.集合名稱.remove(<query>,{justOne:<boolean>})
參數query:可選,刪除的文檔的條件
參數justOne:可選,如果設爲true或1,則只刪除一條,默認false,表示刪除多條
查詢:find() db.集合名稱.find({條件文檔})
查詢一個:findOne() db.集合名稱.findOne({條件文檔})
將結果格式化:方法pretty(): db.集合名稱.find({條件文件}).pretty()
比較運算符
小於:$lt (less than)
小於等於:$lte (less than equal)
大於:$gt (greater than)
大於等於:$gte
不等於:$ne
例: db.stu.find({age:{$gte:18}})
範圍: “$in” , “nin”
例: db.stu.find({age:{$in:[18:28:38]}})
邏輯運算符
And:
db.stu.find({age:{j$gte:18},gender:true})
Or:
Db.stu.find({$or:[{age:{}$gt:18}],{gender:false}})
Db.stu.find({$or:{$gt:18}},{gender:true}],name:’guojing’)
$in $nin
Db.stu.find({age:{$in:[18,28,38]}})
Re正則
Db.products.find({sku:/^abc/})
Db.products.find({sku:{regex:’789$’}})
Limit和skip
讀取指定數量文檔: db.集合名稱.find().limit(NUMBER)
查詢2條學生信息
db.stu.find().limit(2)
跳過指定數量的文檔: db.集合名稱.find().skip(NUMBER)
Db.stu.find().skip(2)
Db.stu.find().limit(4).skip(5)
自定義查詢:
使用$where後面寫一個函數:
Db.stu.find({$where:function(){return this.age>30;}})
投影:在查詢的結果中,只選擇必要的字段
Db.集合名稱.find({},{字段名稱:1},...)
參數爲字段與值,值爲1表示顯示,值爲0不顯示
特殊:對於_id列默認是顯示,如果不顯示需要明確設置爲0
Db.stu.find({},{_id:0,name:1,gender:1})
升序降序 1 / -1
Db.stu.find().sort({age:1})
Db.stu.find().sort({age:-1})
Db.stu.find().sort({age:-1,gender:-1})
查詢所有隻有字段名字:
Db.stu.find({},{name:1,_id:0})
統計個數:
Db.集合名稱.find({條件}).count()
Db.集合名稱.count({條件}).count()
Db.stu.find({gender:true}).count()
Db.stu.count({age:{$gt:20},gender:true})
消除重複
Db.集合名稱.distinct(‘去重字段’,{條件})
Db.stu.distinct(‘hometown’,{age:{$gt:18}})
聚合 aggregate
Aggregate基於數據處理的聚合管道,每個文檔通過一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組、過濾等功能,然後經過一系列的處理,輸出相應的結果。
Db.集合名稱.aggregate({管道:{表達式}})
常用的管道:
$group: 將集合中的文檔分組,可用於統計結果
$match: 過濾數據,只輸出符合條件的文檔
$project: 修改輸入文檔的結構,如重命名、增加、刪除字段、創建計算結果
$sort: 將輸入文檔排序後輸出
$limit: 限制聚合管道返回的文檔數
$skip: 跳過指定數量的文檔,並返回餘下的文檔
$unwind: 將數組類型的字段進行拆分
表達式:
$sum: 計算總和, $sum:1 表示以一倍計數
$avg: 計算平均值
$min: 獲取最小值
$max: 獲取最大值
$push: 在結束文檔中插入值到一個數組中
$first: 根據資源文檔的排序獲取第一個文檔數據
$last: 根據資源文檔的排序獲取最後一個文檔數據
實例化pytmong
from pymongo import MongoClient
#實例化client,建立連接 。如果是本機(內容可以不寫)
client = MongoClient(host="127.0.0.1",port=27017)
collection = client["test"]["t251"]
#插入一條數據 _id 自動隨機生成 (insert接收字典,返回objectID)
# ret1 = collection.insert({"name":"xiaowang","age":10})
# collection.insert( item )
#插入多條數據
# data_list = [{"name":"test{}".format(i)} for i in range(10)]
# collection.insert_many(data_list)
#查詢一個記錄
# t = collection.find_one({"name":"xiaowang"})
#查詢所有記錄
t = collection.find({"name":"xiaowang"})
print(t) # t 是遊標集合對象,取值只能遍歷一次
List(t) # (強制類型轉換爲列表)
# insert_many接收一個列表,列表中爲所有要插入的字典
t = self.collection.insert_many(item_list)
# t.inserted_ids爲所有插入的id
for i in t.inserted_ids:
Print(i)
# find_one查找並且返回一個結果,接收一個字典形式的條件
# find 返回所有滿足條件的結果,如果條件爲空,則返回數據的所有
# update_one更新一條數據
# update_many 跟新全部數據
# delete_one 刪除一條數據
# delete_many 刪除所有滿足條件的數據
終端命令
數據備份:
mongodump -h dbhost -d dbname -o dbdirectory
-h : 服務器地址
-d : 需要備份的數據庫名稱
-o : 備份的數據存放位置
mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak
數據恢復:
mongorestore -h dbhost -d dbname -o dbdirectory
-h : 服務器地址
-d : 需要恢復的數據庫名稱
--dir : 備份的數據所在位置
例:mongorestore -h 192.168.196.128:27017 -d newdb--dir ~/Desktop/test1bak/olddb
添加索引
在默認情況下創建的索引均不是唯一索引。
創建唯一索引:
db.t1.ensureIndex({"name":1},{"unique":true})
創建唯一索引並消除重複:
db.t1.ensureIndex({"name":1},{"unique":true,"dropDups":true})
建立聯合索引(什麼時候需要聯合索引):
db.t1.ensureIndex({name:1,age:1})
查看當前集合的所有索引:
db.t1.getIndexes()
刪除索引:
db.t1.dropIndex('索引名稱')
Redis
中文文檔: http://www.redis.cn/commands.html
Redis-cli 進入redis
Select 0 選擇數據庫0
Keys * 查看當前數據庫
Type 數據名 : 產看當前數據類型 zset 有序類型,set無序類型
Fluchdb清空當前db
1、clone github scrapy-redis源碼文件
git clone https://github.com/rolando/scrapy-redis.git
2、研究項目自帶的三個demo
mv scrapy-redis/example-project ~/scrapyredis-project
Scrapy_redis路徑過濾介紹:
將request對象生成指紋,並不會帶上headers進行生成,因爲請求過程中,cookie會不同,如果帶上headers一起生成指紋,就會出現,相同的路徑生成的指紋不同。
Scrapy_redis如何生成指紋的?
F = Hashlib.sha1()
Celery
Celery是一個任務隊列,同時支持任務調度。
Backend: 後臺,如redis
Broker:相當於消息中間件
三方擴展包
Tesseract 光學識別庫
圖像翻譯成文字的COR庫.識別率不穩定,圖片對比度越明顯真確率越高。
安裝:
sudo apt-get install tesseract-ocr
pip install pytesseract
在終端中調用Tesseract
tesseract abc.jpg test
Python中使用pytesseract識別圖片,需要使用PIL模塊中的Image讀取後的數據:
Import pytesseract
from PIL import.open(jpg)
image = Image.open(jpg)
pytesseract.image_to_string(image)
scrapy框架
Scrapy 使用了 Twisted['twɪstɪd]異步網絡框架,可以加快我們的下載速度。
創建一個scrapy項目
scrapy startproject mySpider
生成一個爬蟲
cd mySpider
scrapy genspider itcast "itcast.cn”
提取數據
完善spider,使用xpath等方法
保存數據
pipeline中保存數據
運行:
Scrapy crawl itcast
邏輯、方法
注意:
1 、 scrapy框架中提供的extract_first()方法,獲取不到值會顯示None,可以省去if判斷邏輯。
2 、 在使用yield item 給pielines.py傳參時,需要將settings.py中的ITEM_PIPELINES(註釋打開)設置執行pipeline順序,框架纔會採用yield傳參,並按順序執行。
3 、 yield 傳遞的參數必須是:Request; BaseItem; dict; None四中類型。
4 、 需要爬取的url地址必須屬於allowed_domains下的連接,超出範圍,需要添加新的範圍到allowed_domains中。
5 、 response.xpath() 返回的是一個含有selector對象的列表。
6 、 item保存到mongodb中時,需要使用dict(item)進行轉換。
7 、 allowed_domains =[‘abdc.com’]如果範圍設置不正確,導致沒有結果。
選擇器提取字符串:
1、extract() 返回一個包含有在字符串數據的列表
2、extract_first() 返回列表中的一個字符串
方法:
Spiders中的每一個(爬蟲.py)中的類屬性name=”xxx”,對應pipelines.py中一個process_item(self,item,sipder)中的sipder.name。
items.py中可以定義多個TencentItem類,pipelines.py中使用isinstance(item,TencentItem)判斷使用的是哪個item。
Item.Field()是個字典。
可以通過logging模塊中的logging.warning(xxxx)將內容寫到日誌中。(debug;info;)
使用logger = logging.getLogger(__name__)方法可以將報錯的當前Py文件顯示出來,方便差錯。Logger.warning(xxxx)
Logging.basicConfig(設置log日誌保存樣式,百度搜編寫格式)
scrapy.Request(next_page_url,callback = self.parse)構造一個requsets請求,傳入url,設置執行函數。如果還行函數類型相同,可以使用同樣個parse,否則自己設置一個請求函數。
構造一個請求Request(url,dont_fileter=True)如果不指定callback。默認會將請求經過parse函數處理。
通過重寫Spider中的def start_requests(self):方法,可以實現自定義方式的關於start_urls的請求。比如添加headers、cookies等。
Scrapy GET請求
scrapy.Request知識點:
scrapy.Request(url, [ callback,method=’GET’,headers,body,cookies,meta,dont_filter=False ] )注:[]中的參數表示可選。
Meta : 傳參(item)時需要和請求一起傳遞到下一個函數中調用。
Dont_filter=False :表示默認過濾url,相同的url只請求一次。
官方文檔:http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html
scrapy模擬POST請求(登陸之發送)
使用scrapy發送Post請求的3中方式:
1、scrapy.FormRequest(url,formdata ={},callback=’’)
2、Scraoy.Request(url,method=”POST”,dody=’’)
3、Scrapy.FormRequest.from_response(response,formdata={},callbak=) # 自動從response中尋找form表單。
Scrapy.FormRequest知識點:
Scrapy.FormRequest.from_response()
注意:只能單獨的表單提交界面,並且頁面中的form表單中可以直接找到action="/login/../.."屬性,不能是js生成的。才能使用from_response方法請求。
使用formdata攜帶需要的post數據
Yield
可以通過添加不同的數據字段,實現函數調用或數據提取前的判斷(通過加if判斷在pipilines.py中使用不同的函數調用,或者在代碼中使用不同的yield函數。)。
item['type'] = "讀書"
yield scrapy.Request(
item["s_href"],
callback=self.parse_cate_content,
meta={"item": deepcopy(item)},
)
yield item
想要在pipelines.py中獲得item,就需要在最後調用的函數中回傳item。
Pipelines.py 管道
import something
class SomethingPipeline(object):
def __init__(self):
# 可選實現,做參數初始化等
# doing something
def process_item(self, item, spider):
# item (Item 對象) – 被爬取的item
# spider (Spider 對象) – 爬取該item的spider
# 這個方法必須實現,每個item pipeline組件都需要調用該方法,
# 這個方法必須返回一個 Item 對象,被丟棄的item將不會被之後的pipeline組件所處理。
return item
def open_spider(self, spider):
# spider (Spider 對象) – 被開啓的spider
# 可選實現,當spider被開啓時,這個方法被調用。
def close_spider(self, spider):
# spider (Spider 對象) – 被關閉的spider
# 可選實現,當spider被關閉時,這個方法被調用
Setting.py中設置
ITEM_PIPELINES = {
'Something.pipelines.SomethingPipeline: 300,
......
......
}
Middlewares.py 中間件
下載中間件是處於引擎(crawler.engine)和下載器(crawler.engine.download())之間的一層組件,可以有多個下載中間件被加載運行。
當引擎傳遞請求給下載器的過程中,下載中間件可以對請求進行處理 (例如增加http header信息,增加proxy信息等);
在下載器完成http請求,傳遞響應給引擎的過程中, 下載中間件可以對響應進行處理(例如進行gzip的解壓等)
DOWNLOADER_MIDDLEWARES = {
'mySpider.middlewares.MyDownloaderMiddleware': 543,
}
Setting設置
# -*- coding: utf-8 -*-
# Scrapy settings for yangguang project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://doc.scrapy.org/en/latest/topics/settings.html
# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
# redis增量爬蟲設置
# 指定那個去重方法給request對象去重
# 調度器 指定scheduler隊列
# 讓redis持續保存數據 設置False,會在關閉redis的時候清空redis
# 設置路徑操作redis
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True
REDIS_URL = "redis://127.0.0.1:6379"
# scrapy_redis實現的items保存到redis的pipeline。
ITEM_PIPELINES = {
......
'scrapy_redis.pipelines.RedisPipeline': 400,
}
# 也可以寫成
# REDIS_HOST = “192.168.207.124”
# REDIS_PORT = 6379
-----------------------------------------------------------------------------------------------
# 項目名
BOT_NAME = 'yangguang'
# 爬蟲位置
SPIDER_MODULES = ['yangguang.spiders']
# 新建爬蟲位置
NEWSPIDER_MODULE = 'yangguang.spiders'
# 查看cookies傳遞路徑
COOKIES_DEBUG =True
# 設置報警級別
LOG_LEVEL="WARNING"
# 設置log日誌保存的地址(終端中不再顯示)
# LOG_FILE="./log.log"
# 設置請求中的 User-Agent(瀏覽器的身份標識,用戶代理)
#USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3278.0 Safari/537.36'
# 遵守robots協議.(網站中允許爬去的範圍)
ROBOTSTXT_OBEY = True
# 設置mongo存儲位置爲本機
MONGO_HOST="local_host"
# 配置Scrapy執行的最大併發請求(默認值:16)
#CONCURRENT_REQUESTS = 32
#配置對同一網站要求延遲(默認值:0秒)
#DOWNLOAD_DELAY = 3
# 每個域名請求併發數
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
# 每個ip請求併發數
#CONCURRENT_REQUESTS_PER_IP = 16
# 禁用cookie(默認啓用)
#COOKIES_ENABLED = False
# 禁用Telnet控制檯(默認啓用)
#TELNETCONSOLE_ENABLED = False
# 覆蓋默認請求頭 (注:User-Agent不能寫到這裏)
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# 啓用或禁用spider中間件
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'yangguang.middlewares.YangguangSpiderMiddleware': 543,
#}
# 啓用或禁用downloader中間件
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'yangguang.middlewares.YangguangDownloaderMiddleware': 543,
#}
# 啓用或禁用擴展
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
#配置項目管道
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
# 開啓ITEM_PIPELINES,yield 才能接收item返回到pipelines.py中調用,存入mongodb數據庫。 (300是權重值,越小越先執行)
ITEM_PIPELINES = {
'yangguang.pipelines.YangguangPipeline': 300,
}
# 啓用並配置自動節流閥擴展(默認禁用) 防止請求過快,將服務器抓崩。
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# 啓用和配置HTTP緩存(默認禁用)
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
Scrapy
(scrapy.Spider) :普通爬蟲,再次啓動會從新爬去數據,start_url地址請求重複,造成數據冗餘。
scrapy genspider itcast "itcast.cn”
(CrawlSpider) :自動提取url地址
生成crawlspider的命令:
Scrapy genspider -t crawl csdn “csdn.cn”
Rule(LinkExtractor(allow=r'可以是不完整的url'), callback='parse_item',follow=True),
# callback 提取出來的url地址的response會交給callback處理
# follow 當前url地址的響應是夠重新進過rules來提取url地址
# allow中寫正則
Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
Parse函數有特殊功能,不能定義。
Scrapy_redis
Scrapy_redis在scrapy的基礎上實現了更多,更強大的功能,具體體現在:reqeust去重,爬蟲持久化,和輕鬆實現分佈式
“””spider that reads urls from redis queue (myspider:start_urls)”””
# 指定redis_key的讀取(鍵)位置,程序會以Pop的讀取方式,可以實現多臺服務器同時完成一個任務,實現分佈式爬蟲。redis中存儲的myspider:start_urls鍵所提供的(路徑)數據。
redis_key = “myspider:start_urls”
(RedisSpider) :分佈式爬蟲,非重複,可間斷,連續自動提取url地址,發送請求
爬蟲的創建:
Scrapy startproject myspider
Scrapy genspider dangdang dangdang.com
from scrapy_redis.spiders import RedisSpider
class DangdangSpider(RedisSpider):
name = 'dangdang'
allowed_domains = ['dangdang.com']
# start_urls = ['http://book.dangdang.com/']
redis_key = "dangdang"
def parse(self, response):
終端運行:
Scrapy crawl dangdang
Redis中添加第一個請求地址:
redis-cli
lpush dangdang http://book.dangdang.com/
(RedisCrawlSpider) :自動提取url地址,實現分佈式爬蟲
from scrapy_redis.spiders import RedisCrawlSpider
class MyCrawler(RedisCrawlSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
name = 'mycrawler_redis'
redis_key = 'spider'
allowed_domain = []
rules = (
# restrict_xpaths不需要精確匹配指定的url地址,
Rule(LinkExtractor(restrict_xpaths=('//div[@class="...."]')或allow=r'Items/'), callback='parse_item', follow=True),
)
# def __init__(self, *args, **kwargs):
# # Dynamically define the allowed domains list.
# domain = kwargs.pop('domain', '')
# self.allowed_domains = filter(None, domain.split(','))
# super(MyCrawler, self).__init__(*args, **kwargs)
def parse_page(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,
}
LinkExtractor常見參數
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
import re
class AmazonSpider(RedisCrawlSpider):
name = 'amazon'
allowed_domains = ['amazon.cn']
# start_urls = ['https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/b/ref=sd_allcat_books_l1?ie=UTF8&node=658390051']
redis_key = "amazon"
rules = (
#匹配大分類的url地址和小分類的url
Rule(LinkExtractor(restrict_xpaths=("//div[@class='categoryRefinementsSection']/ul/li",)), follow=True),
#匹配圖書的url地址
Rule(LinkExtractor(restrict_xpaths=("//div[@id='mainResults']/ul/li//h2/..",)),callback="parse_book_detail"),
#列表頁翻頁
Rule(LinkExtractor(restrict_xpaths=("//div[@id='pagn']",)),follow=True),
)
def parse_book_detail(self,response):
# with open(response.url.split("/")[-1]+".html","w",encoding="utf-8") as f:
# f.write(response.body.decode())
item = {}
item["book_title"] = response.xpath("//span[@id='productTitle']/text()").extract_first()
item["book_publish_date"] = response.xpath("//h1[@id='title']/span[last()]/text()").extract_first()
item["book_author"] = response.xpath("//div[@id='byline']/span/a/text()").extract()
# item["book_img"] = response.xpath("//div[@id='img-canvas']/img/@src").extract_first()
item["book_price"] = response.xpath("//div[@id='soldByThirdParty']/span[2]/text()").extract_first()
item["book_cate"] = response.xpath("//div[@id='wayfinding-breadcrumbs_feature_div']/ul/li[not(@class)]/span/a/text()").extract()
item["book_cate"] = [i.strip() for i in item["book_cate"]]
item["book_url"] = response.url
item["book_press"] = response.xpath("//b[text()='出版社:']/../text()").extract_first()
# item["book_desc"] = re.findall(r'<noscript>.*?<div>(.*?)</div>.*?</noscript>',response.body.decode(),re.S)
# item["book_desc"] = response.xpath("//noscript/div/text()").extract()
# item["book_desc"] = [i.strip() for i in item["book_desc"] if len(i.strip())>0 and i!='海報:']
# item["book_desc"] = item["book_desc"][0].split("<br>",1)[0] if len(item["book_desc"])>0 else None
print(item)
報文
1 、Overridden settings: settings.py中設置的內容。
2 、 Dumping Scrapy stats: 爬取數據的統計內容。
3 、關於正則中出現的錯誤:
TypeError: int() argument must be a string, a bytes-like object or a number, not '_sre.SRE_Match'
解決:缺少.group()方法提取。
re.search(r” ”,data).group(1)
4 、 LinkExtractor :連接提取器
5 、 TelnetConsole 錯誤
因爲程序手動關閉後,並沒有真正的結束,再次啓動會提示內存中暫用有程序。並不影響後續代碼的執行和數據的獲取。不用修改。
Crontab軟件:爬蟲定時執行
安裝:apt-get install cron(服務器環境下默認安裝有)
使用:crontab -e 進入編輯頁面(第一次會讓你選擇編輯器)
Crontab -l 查看當前定時任務
常用數據單詞
URL編碼:%3a%2f%.....
Location 地址
擴展
安裝第三方模塊:
1 、Pip install 包名
2 、壓縮包文件中有setup.py文件,可以直接使用python setup.py 進行安裝
3 、 ***.whl 文件 安裝方法:pip install ***.whl
第三方模塊:
1、requests
Import requests 導入模塊
2、lxml
from lxml import etree 導入etree功能
文本格式:
XML :
被設計用來傳輸和存儲數據。(同JSON一樣用來傳輸數據)
HTML :
被設計用來顯示數據。
CSV :
CSV是一種通用的、相對簡單的文件格式。廣泛的應用是在程序之間轉移表格數據。Excel表格工具可以直接打開。
PIL 模塊,可以實現截圖。注意,需要將瀏覽器寬高固定,要不然截圖位置無法定位。
Iframe 前端HTML中的一種框架,可以在一個html頁面中嵌套另一個iframe頁面。
PhantomJS:無邊界瀏覽器(selenium中加載到內存)
瞭解方法:顯式等待/隱式等待 (爬蟲day06-07)
Hash 哈希
又稱:散列、字典
linux(ubuntu)???phantomjs <http://www.cnblogs.com/lgh344902118/p/6369054.html>
phantomjs各個版本的下載路徑
<https://bitbucket.org/ariya/phantomjs/downloads/>
安裝方法:
1.9.8那個版本的phantomjs在Python3中也可以用
<https://www.cnblogs.com/lgh344902118/p/6369054.html>
列表排序
Lambda表達式:↓
終端命令:
Ctrl + Z 並沒有將當前程序結束,而是隱藏到後臺。
通過:ps aux | grep scrapy 可以查看對應文件運行情況
殺死程序: kill 編碼
必殺: Kill 9
Pycharm中調bug
工具
Chremo中安裝JSONView插件。
網頁在線解碼
網頁在線格式轉換
Pychem
Atom
總結
### xpath的包含
- `//div[contains(@class,'i')]`
實現爬蟲的套路
- 準備url
- 準備start_url
- url地址規律不明顯,總數不確定
- 通過代碼提取下一頁的url
- xpath
- 尋找url地址,部分參數在當前的響應中(比如,當前頁碼數和總的頁碼數在當前的響應中)
- 準備url_list
- 頁碼總數明確
- url地址規律明顯
- 發送請求,獲取響應
- 添加隨機的User-Agent,反反爬蟲
- 添加隨機的代理ip,反反爬蟲
- 在對方判斷出我們是爬蟲之後,應該添加更多的headers字段,包括cookie
- cookie的處理可以使用session來解決
- 準備一堆能用的cookie,組成cookie池
- 如果不登錄
- 準備剛開始能夠成功請求對方網站的cookie,即接收對方網站設置在response的cookie
- 下一次請求的時候,使用之前的列表中的cookie來請求
- 如果登錄
- 準備多個賬號
- 使用程序獲取每個賬號的cookie
- 之後請求登錄之後才能訪問的網站隨機的選擇cookie
- 提取數據
- 確定數據的位置
- 如果數據在當前的url地址中
- 提取的是列表頁的數據
- 直接請求列表頁的url地址,不用進入詳情頁
- 提取的是詳情頁的數據
- 1. 確定url
- 2. 發送請求
- 3. 提取數據
- 4. 返回
- 如果數據不在當前的url地址中
- 在其他的響應中,尋找數據的位置
- 1. 從network中從上往下找
- 2. 使用chrome中的過濾條件,選擇出了js,css,img之外的按鈕
- 3. 使用chrome的search all file,搜索數字和英文
- 數據的提取
- xpath,從html中提取整塊的數據,先分組,之後每一組再提取
- re,提取max_time,price,html中的json字符串
- json
- 保存
- 保存在本地,text,json,csv
- 保存在數據庫