SuperSpider
== 萬字長文,建議使用目錄點擊查閱,有助于高效開發,建議點贊收藏 ==
文章目錄
- SuperSpider
- Request抓取思路步驟
- 多級頁面資料抓取思路
- UserAgent反爬處理
- Cookie反爬
- Cookie引數使用
- CookieJar物件轉換為Cookies字典
- requests模塊引數總結
- requests.get()
- requests.post()
- request.session()
- 作用與應用場景
- 使用方法
- response
- response.text 和response.content的區別:
- 動態加載資料抓取-Ajax
- json決議模塊
- json.loads(json)
- json.dump(python,f,ensure_ascii=False)
- jsonpath
- json模塊總結
- 控制臺抓包
- 代理設定
- 定義及分類
- 普通代理思路
- 普通代理
- 私密代理+獨享代理
- 私密代理+獨享代理 - 示例代碼
- 建立自己的代理IP池 - 開放代理 | 私密代理
- 拉勾網阿布云代理
- unicode與encode
- 決議模塊總結
- re正則決議
- lxml+xpath決議
- xpath運算式
- 資料持久化
- mysql
- Mysql模板
- mongodb
- mongodb模板
- Json
- Json模板
- json常用操作
- json存盤串列
- CSV模板
- txt模板
- redis增量URl爬蟲實作思路
- 休眠設定
- 時間引數
- 打碼平臺
- 云詞
- 多執行緒爬蟲
- 應用場景
- 多執行緒爬蟲示例【豆瓣】
- selenium+PhantomJS/Chrome/Firefox
- selenium
- 繞過selenium檢測
- selenium對cookie的處理
- 獲取cookie
- 洗掉cookie
- selenium使用代理ip
- selenium替換user-agent
- 指定埠遙控
- PhantomJS瀏覽器
- 百度示例代碼
- 瀏覽器物件(browser)方法
- Selenium 定位節點八種方法
- 貓眼電影示例
- chromedriver設定無界面模式
- selenium - 滑鼠操作
- selenium處理iframe反爬
Request抓取思路步驟
【1】先確定是否為動態加載網站
【2】找URL規律
【3】正則運算式 | xpath運算式
【4】定義程式框架,補全并測驗代碼
- 細節要點:查看頁面編碼charset、請求時是否需要驗證verify=FALSE
多級頁面資料抓取思路
【1】整體思路
1.1> 爬取一級頁面,提取 所需資料+鏈接,繼續跟進
1.2> 爬取二級頁面,提取 所需資料+鏈接,繼續跟進
1.3> ... ...
【2】代碼實作思路
2.1> 避免重復代碼 - 請求、決議需定義函式
UserAgent反爬處理
【1】基于User-Agent反爬
1.1) 發送請求攜帶請求頭: headers={'User-Agent' : 'Mozilla/5.0 xxxxxx'}
1.2) 多個請求時隨機切換User-Agent
a) 定義py檔案存放大量User-Agent,匯入后使用random.choice()每次隨機選擇
b) 使用fake_useragent模塊每次訪問隨機生成User-Agent
from fake_useragent import UserAgent
agent = UserAgent().random
細節要點:pycharm中下載fake-useragent
【2】回應內容存在特殊字符
解碼時使用ignore引數
html = requests.get(url=url, headers=headers).content.decode('', 'ignore')
Cookie反爬
Cookie引數使用
-
cookies引數的形式:字典
cookies = {"cookie的name":"cookie的value"}- 該字典對應請求頭中Cookie字串,以分號、空格分割每一對字典鍵值對
- 等號左邊的是一個cookie的name,對應cookies字典的key
- 等號右邊對應cookies字典的value
-
cookies引數的使用方法
response = requests.get(url, cookies) -
將cookie字串轉換為cookies引數所需的字典:
cookies_dict = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')} -
注意:cookie一般是有過期時間的,一旦過期需要重新獲取
CookieJar物件轉換為Cookies字典
使用requests獲取的resposne物件,具有cookies屬性,該屬性值是一個cookieJar型別,包含了對方服務器設定在本地的cookie,我們如何將其轉換為cookies字典呢?
-
轉換方法
cookies_dict = requests.utils.dict_from_cookiejar(response.cookies) -
其中response.cookies回傳的就是cookieJar型別的物件
-
requests.utils.dict_from_cookiejar函式回傳cookies字典
requests模塊引數總結
【1】方法一 : requests.get()
【2】引數
2.1) url
2.2) headers
2.3) timeout
2.4) proxies
【3】方法二 :requests.post()
【4】引數
data
requests.get()
-
思路
【1】url 【2】proxies -> {} proxies = { 'http':'http://1.1.1.1:8888', 'https':'https://1.1.1.1:8888' } 【3】timeout 【4】headers 【5】cookies
requests.post()
-
適用場景
【1】適用場景 : Post型別請求的網站 【2】引數 : data={} 2.1) Form表單資料: 字典 2.2) res = requests.post(url=url,data=data,headers=headers) 【3】POST請求特點 : Form表單提交資料 data : 字典,Form表單資料 -
pycharm中正則處理headers和formdata
【1】pycharm進入方法 :Ctrl + r ,選中 Regex 【2】處理headers和formdata (.*): (.*) "$1": "$2", 【3】點擊 Replace All -
經典Demo有道翻譯
request.session()
- requests模塊中的Session類能夠自動處理發送請求獲取回應程序中產生的cookie,進而達到狀態保持的目的,接下來我們就來學習它
作用與應用場景
- requests.session的作用
- 自動處理cookie,即 下一次請求會帶上前一次的cookie
- requests.session的應用場景
- 自動處理連續的多次請求程序中產生的cookie
使用方法
session實體在請求了一個網站后,對方服務器設定在本地的cookie會保存在session中,下一次再使用session請求對方服務器的時候,會帶上前一次的cookie
session = requests.session() # 實體化session物件
response = session.get(url, headers, ...)
response = session.post(url, data, ...)
- session物件發送get或post請求的引數,與requests模塊發送請求的引數完全一致
response
response.text 和response.content的區別:
- response.text
- 型別:str
- 解碼型別: requests模塊自動根據HTTP 頭部對回應的編碼作出有根據的推測,推測的文本編碼
- response.content
- 型別:bytes
- 解碼型別: 沒有指定
動態加載資料抓取-Ajax
-
特點
【1】右鍵 -> 查看網頁原始碼中沒有具體資料 【2】滾動滑鼠滑輪或其他動作時加載,或者頁面區域重繪 -
抓取
【1】F12打開控制臺,頁面動作抓取網路資料包 【2】抓取json檔案URL地址 2.1) 控制臺中 XHR :異步加載的資料包 2.2) XHR -> QueryStringParameters(查詢引數) -
經典Demo:豆瓣電影
json決議模塊
json.loads(json)
【1】作用 : 把json格式的字串轉為Python資料型別
【2】示例 : html = json.loads(res.text)
json.dump(python,f,ensure_ascii=False)
【1】作用
把python資料型別 轉為 json格式的字串,一般讓你把抓取的資料保存為json檔案時使用
【2】引數說明
2.1) 第1個引數: python型別的資料(字典,串列等)
2.2) 第2個引數: 檔案物件
2.3) 第3個引數: ensure_ascii=False 序列化時編碼
【3】示例代碼
# 示例1
import json
item = {'name':'QQ','app_id':1}
with open('小米.json','a') as f:
json.dump(item,f,ensure_ascii=False)
# 示例2
import json
item_list = []
for i in range(3):
item = {'name':'QQ','id':i}
item_list.append(item)
with open('xiaomi.json','a') as f:
json.dump(item_list,f,ensure_ascii=False)
jsonpath
jsonpath使用示例
book_dict = {
"store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
from jsonpath import jsonpath
print(jsonpath(book_dict, '$..author')) # 如果取不到將回傳False # 回傳串列,如果取不到將回傳False

json模塊總結
# 爬蟲最常用
【1】資料抓取 - json.loads(html)
將回應內容由: json 轉為 python
【2】資料保存 - json.dump(item_list,f,ensure_ascii=False)
將抓取的資料保存到本地 json檔案
# 抓取資料一般處理方式
【1】txt檔案
【2】csv檔案
【3】json檔案
【4】MySQL資料庫
【5】MongoDB資料庫
【6】Redis資料庫
控制臺抓包
-
打開方式及常用選項
【1】打開瀏覽器,F12打開控制臺,找到Network選項卡 【2】控制臺常用選項 2.1) Network: 抓取網路資料包 a> ALL: 抓取所有的網路資料包 b> XHR:抓取異步加載的網路資料包 c> JS : 抓取所有的JS檔案 2.2) Sources: 格式化輸出并打斷點除錯JavaScript代碼,助于分析爬蟲中一些引數 2.3) Console: 互動模式,可對JavaScript中的代碼進行測驗 【3】抓取具體網路資料包后 3.1) 單擊左側網路資料包地址,進入資料包詳情,查看右側 3.2) 右側: a> Headers: 整個請求資訊 General、Response Headers、Request Headers、Query String、Form Data b> Preview: 對回應內容進行預覽 c> Response:回應內容
代理設定
定義及分類
代理ip的匿名程度,代理IP可以分為下面三類:
1.透明代理(Transparent Proxy):透明代理雖然可以直接“隱藏”你的IP地址,但是還是可以查到你是誰,
2.匿名代理(Anonymous Proxy):使用匿名代理,別人只能知道你用了代理,無法知道你是誰,
3.高匿代理(Elite proxy或High Anonymity Proxy):高匿代理讓別人根本無法發現你是在用代理,所以是最好的選擇,
代理服務請求使用的協議可以分為:
1.http代理:目標url為http協議
2.https代理:目標url為https協議
3.socks隧道代理(例如socks5代理)等:
socks 代理只是簡單地傳遞資料包,不關心是何種應用協議(FTP、HTTP和HTTPS等),
socks 代理比http、https代理耗時少,
socks 代理可以轉發http和https的請求
普通代理思路
【1】獲取代理IP網站
西刺代理、快代理、全網代理、代理精靈、阿布云、芝麻代理... ...
【2】引數型別
proxies = { '協議':'協議://IP:埠號' }
proxies = {
'http':'http://IP:埠號',
'https':'https://IP:埠號',
}
普通代理
# 使用免費普通代理IP訪問測驗網站: http://httpbin.org/get
import requests
url = 'http://httpbin.org/get'
headers = {'User-Agent':'Mozilla/5.0'}
# 定義代理,在代理IP網站中查找免費代理IP
proxies = {
'http':'http://112.85.164.220:9999',
'https':'https://112.85.164.220:9999'
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)
私密代理+獨享代理
【1】語法結構
proxies = { '協議':'協議://用戶名:密碼@IP:埠號' }
【2】示例
proxies = {
'http':'http://用戶名:密碼@IP:埠號',
'https':'https://用戶名:密碼@IP:埠號',
}
私密代理+獨享代理 - 示例代碼
import requests
url = 'http://httpbin.org/get'
proxies = {
'http': 'http://309435365:szayclhp@106.75.71.140:16816',
'https':'https://309435365:szayclhp@106.75.71.140:16816',
}
headers = {
'User-Agent' : 'Mozilla/5.0',
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)
建立自己的代理IP池 - 開放代理 | 私密代理
"""
收費代理:
建立開放代理的代理IP池
思路:
1、獲取到開放代理
2、依次對每個代理IP進行測驗,能用的保存到檔案中
"""
import requests
class ProxyPool:
def __init__(self):
self.url = '代理網站的API鏈接'
self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36'}
# 打開檔案,用來存放可用的代理IP
self.f = open('proxy.txt', 'w')
def get_html(self):
html = requests.get(url=self.url, headers=self.headers).text
proxy_list = html.split('\r\n')
for proxy in proxy_list:
# 依次測驗每個代理IP是否可用
if self.check_proxy(proxy):
self.f.write(proxy + '\n')
def check_proxy(self, proxy):
"""測驗1個代理IP是否可用,可用回傳True,否則回傳False"""
test_url = 'http://httpbin.org/get'
proxies = {
'http' : 'http://{}'.format(proxy),
'https': 'https://{}'.format(proxy)
}
try:
res = requests.get(url=test_url, proxies=proxies, headers=self.headers, timeout=2)
if res.status_code == 200:
print(proxy,'\033[31m可用\033[0m')
return True
else:
print(proxy,'無效')
return False
except:
print(proxy,'無效')
return False
def run(self):
self.get_html()
# 關閉檔案
self.f.close()
if __name__ == '__main__':
spider = ProxyPool()
spider.run()
拉勾網阿布云代理
import json
import re
import time
import requests
import multiprocessing
from job_data_analysis.lagou_spider.handle_insert_data import lagou_mysql
class HandleLaGou(object):
def __init__(self):
#使用session保存cookies資訊
self.lagou_session = requests.session()
self.header = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
self.city_list = ""
#獲取全國所有城市串列的方法
def handle_city(self):
city_search = re.compile(r'www\.lagou\.com\/.*\/">(.*?)</a>')
city_url = "https://www.lagou.com/jobs/allCity.html"
city_result = self.handle_request(method="GET",url=city_url)
#使用正則運算式獲取城市串列
self.city_list = set(city_search.findall(city_result))
self.lagou_session.cookies.clear()
def handle_city_job(self,city):
first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%city
first_response = self.handle_request(method="GET",url=first_request_url)
total_page_search = re.compile(r'class="span\stotalNum">(\d+)</span>')
try:
total_page = total_page_search.search(first_response).group(1)
print(city,total_page)
#由于沒有崗位資訊造成的exception
except:
return
else:
for i in range(1,int(total_page)+1):
data = {
"pn":i,
"kd":"web"
}
page_url = "https://www.lagou.com/jobs/positionAjax.json?city=%s&needAddtionalResult=false"%city
referer_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%city
#referer的URL需要進行encode
self.header['Referer'] = referer_url.encode()
response = self.handle_request(method="POST",url=page_url,data=data,info=city)
lagou_data = json.loads(response)
job_list = lagou_data['content']['positionResult']['result']
for job in job_list:
lagou_mysql.insert_item(job)
def handle_request(self,method,url,data=None,info=None):
while True:
#加入阿布云的動態代理
proxyinfo = "http://%s:%s@%s:%s" % ('賬號', '密碼', 'http-dyn.abuyun.com', '9020')
proxy = {
"http":proxyinfo,
"https":proxyinfo
}
try:
if method == "GET":
response = self.lagou_session.get(url=url,headers=self.header,proxies=proxy,timeout=6)
elif method == "POST":
response = self.lagou_session.post(url=url,headers=self.header,data=data,proxies=proxy,timeout=6)
except:
# 需要先清除cookies資訊
self.lagou_session.cookies.clear()
# 重新獲取cookies資訊
first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput=" % info
self.handle_request(method="GET", url=first_request_url)
time.sleep(10)
continue
response.encoding = 'utf-8'
if '頻繁' in response.text:
print(response.text)
#需要先清除cookies資訊
self.lagou_session.cookies.clear()
# 重新獲取cookies資訊
first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%info
self.handle_request(method="GET",url=first_request_url)
time.sleep(10)
continue
return response.text
if __name__ == '__main__':
lagou = HandleLaGou()
#所有城市的方法
lagou.handle_city()
print(lagou.city_list)
#引入多行程加速抓取
pool = multiprocessing.Pool(2)
for city in lagou.city_list:
pool.apply_async(lagou.handle_city_job,args=(city,))
pool.close()
pool.join()
unicode與encode
-
unicode: 作用是將unicode編碼轉換成其他編碼的字串,將所有語言統一到unicode中 [如果內容是英文,unicode編碼比ASCII多一倍的存盤空間,同時傳輸需要多一倍的傳輸]
-
encode : 作用是將unicode編碼轉換成其他編碼的字串
-
decode:作用是將其他編碼的字串轉換成unicode編碼,需要指明原來的編碼格式
-
編碼換:
s = ("我愛中國,i love china") s.decode("gb2312").encode("utf-8") -
查看當前編碼
import sys sys.getdefaultencoding()
-
-
python3中用unicode進行編碼,因此能直接用用unicode來編碼:s.encode(“utf-8”)
-
通常情況下window是GB2312編碼
-
linux通常情況下是utf8的編碼
決議模塊總結
re正則決議
import re
pattern = re.compile('正則運算式',re.S)
r_list = pattern.findall(html)

lxml+xpath決議
from lxml import etree
p = etree.HTML(res.text)
r_list = p.xpath('xpath運算式')
【謹記】只要呼叫了xpath,得到的結果一定為'串列'
xpath運算式
-
匹配規則
【1】結果: 節點物件串列 1.1) xpath示例: //div、//div[@class="student"]、//div/a[@title="stu"]/span 【2】結果: 字串串列 2.1) xpath運算式中末尾為: @src、@href、/text() -
最常用
【1】基準xpath運算式: 得到節點物件串列 【2】for r in [節點物件串列]: username = r.xpath('./xxxxxx') 【注意】遍歷后繼續xpath一定要以: . 開頭,代表當前節點 -
豆瓣書籍抓取
import requests from lxml import etree from fake_useragent import UserAgent import time import random class DoubanBookSpider: def __init__(self): self.url = 'https://book.douban.com/top250?start={}' def get_html(self, url): """使用隨機的User-Agent""" headers = {'User-Agent':UserAgent().random} html = requests.get(url=url, headers=headers).text self.parse_html(html) def parse_html(self, html): """lxml+xpath進行資料決議""" parse_obj = etree.HTML(html) # 1.基準xpath:提取每本書的節點物件串列 table_list = parse_obj.xpath('//div[@class="indent"]/table') for table in table_list: item = {} # 書名 name_list = table.xpath('.//div[@class="pl2"]/a/@title') item['name'] = name_list[0].strip() if name_list else None # 描述 content_list = table.xpath('.//p[@class="pl"]/text()') item['content'] = content_list[0].strip() if content_list else None # 評分 score_list = table.xpath('.//span[@class="rating_nums"]/text()') item['score'] = score_list[0].strip() if score_list else None # 評價人數 nums_list = table.xpath('.//span[@class="pl"]/text()') item['nums'] = nums_list[0][1:-1].strip() if nums_list else None # 類別 type_list = table.xpath('.//span[@class="inq"]/text()') item['type'] = type_list[0].strip() if type_list else None print(item) def run(self): for i in range(5): start = (i - 1) * 25 page_url = self.url.format(start) self.get_html(page_url) time.sleep(random.randint(1,2)) if __name__ == '__main__': spider = DoubanBookSpider() spider.run()
資料持久化
mysql
"""
sql 表創建
mysql -uroot -p
create database maoyandb charset utf8;
use maoyandb;
create table maoyantab(
name varchar(100),
star varchar(300),
time varchar(100)
)charset=utf8;
"""
"""
pymysql模塊使用
"""
import pymysql
# 1.連接資料庫
db = pymysql.connect(
'localhost','root','123456','maoyandb',charset='utf8'
)
cur = db.cursor()
# 2.執行sql命令
ins = 'insert into maoyantab values(%s,%s,%s)'
cur.execute(ins, ['肖申克的救贖','主演:張國榮,張曼玉,劉德華','2018-06-25'])
# 3.提交到資料庫執行
db.commit()
cur.close()
db.close()
Mysql模板
import pymysql
# __init__(self):
self.db = pymysql.connect('IP',... ...)
self.cursor = self.db.cursor()
# save_html(self,r_list):
self.cursor.execute('sql',[data1])
self.cursor.executemany('sql', [(),(),()])
self.db.commit()
# run(self):
self.cursor.close()
self.db.close()
mongodb
- https://www.runoob.com/python3/python-mongodb.html 【菜鳥教程】
"""
【1】非關系型資料庫,資料以鍵值對方式存盤,埠27017
【2】MongoDB基于磁盤存盤
【3】MongoDB資料型別單一,值為JSON檔案,而Redis基于記憶體,
3.1> MySQL資料型別:數值型別、字符型別、日期時間型別、列舉型別
3.2> Redis資料型別:字串、串列、哈希、集合、有序集合
3.3> MongoDB資料型別:值為JSON檔案
【4】MongoDB: 庫 -> 集合 -> 檔案
MySQL : 庫 -> 表 -> 表記錄
"""
"""
Linux進入: mongo
>show dbs - 查看所有庫
>use 庫名 - 切換庫
>show collections - 查看當前庫中所有集合
>db.集合名.find().pretty() - 查看集合中檔案
>db.集合名.count() - 統計檔案條數
>db.集合名.drop() - 洗掉集合
>db.dropDatabase() - 洗掉當前庫
"""
import pymongo
# 創建連接物件
connect = pymongo.MongoClient(host='127.0.0.1',port=27017)
# 連接庫物件
db = connect['maoyandb']
# 創建集合物件
myset = db['maoyanset']
# 插入單條資料
# myset.insert_one({'name':'錢天一'})
# 插入多條資料
myset.insert_many[{'name':'張三'},{'name':'李四'},{'name':'王五'}]
mongodb模板
import requests
import re
import time
import random
import pymongo
class MaoyanSpider:
def __init__(self):
self.url = 'https://maoyan.com/board/4?offset={}'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'}
# 三個物件:連接物件、庫物件、庫集合
self.conn = pymongo.MongoClient('127.0.0.1',27017)
self.db = self.conn['maoyandb']
self.myset = self.db['maoyanset']
##提取網頁資料
def get_html(self,url):
html = requests.get(url,url,headers=self.headers).text
self.parse_html(html)
##決議網頁資料
def parse_html(self,html):
regex = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>'
pattern = re.compile(regex,re.S)
r_list = pattern.findall(html)
self.save_html(r_list)
## 資料處理提取
def save_html(self,r_list):
for r in r_list:
item ={}
item['name'] = r[0].strip()
item['star'] = r[1].strip()
item['time'] = r[2].strip()
print(item)
# 存入到mongodb資料庫
self.myset.insert_one(item)
def run(self):
"""程式入口函式"""
for offset in range(0, 91, 10):
url = self.url.format(offset)
self.get_html(url=url)
# 控制資料抓取頻率:uniform()生成指定范圍內的浮點數
time.sleep(random.uniform(0, 1))
if __name__ == '__main__':
spider = MaoyanSpider()
spider.run()
Json
import json
# Demo1
item = {'name':'QQ','e-mail':99362}
with open('qq.json','a')as f:
json.dump(item,f,ensure_ascii=False)
# Demo2
# import json
# item_list =[]
# for i in range(3):
# item = {'name':'QQ','e-mail':'99362'}
# item_list.append(item)
#
# with open('demo2.json','a')as f:
# json.dump(item_list,f,ensure_ascii=False)
Json模板
import requests
from fake_useragent import UserAgent
import time
import random
import re
import json
# 豆瓣電影全堆疊抓取
class DoubanSpider:
def __init__(self):
self.url = 'https://movie.douban.com/j/chart/top_list?'
self.i = 0
# 存入json檔案
self.f = open('douban.json', 'w', encoding='utf-8')
self.all_film_list = []
def get_agent(self):
"""獲取隨機的User-Agent"""
return UserAgent().random
def get_html(self, params):
headers = {'User-Agent':self.get_agent()}
html = requests.get(url=self.url, params=params, headers=headers).text
# 把json格式的字串轉為python資料型別
html = json.loads(html)
self.parse_html(html)
def parse_html(self, html):
"""決議"""
# html: [{},{},{},{}]
item = {}
for one_film in html:
item['rank'] = one_film['rank']
item['title'] = one_film['title']
item['score'] = one_film['score']
print(item)
self.all_film_list.append(item)
self.i += 1
def run(self):
# d: {'劇情':'11','愛情':'13','喜劇':'5',...,...}
d = self.get_d()
# 1、給用戶提示,讓用戶選擇
menu = ''
for key in d:
menu += key + '|'
print(menu)
choice = input('請輸入電影類別:')
if choice in d:
code = d[choice]
# 2、total: 電影總數
total = self.get_total(code)
for start in range(0,total,20):
params = {
'type': code,
'interval_id': '100:90',
'action': '',
'start': str(start),
'limit': '20'
}
self.get_html(params=params)
time.sleep(random.randint(1,2))
# 把資料存入json檔案
json.dump(self.all_film_list, self.f, ensure_ascii=False)
self.f.close()
print('數量:',self.i)
else:
print('請做出正確的選擇')
def get_d(self):
"""{'劇情':'11','愛情':'13','喜劇':'5',...,...}"""
url = 'https://movie.douban.com/chart'
html = requests.get(url=url,headers={'User-Agent':self.get_agent()}).text
regex = '<span><a href=".*?type_name=(.*?)&type=(.*?)&interval_id=100:90&action=">'
pattern = re.compile(regex, re.S)
# r_list: [('劇情','11'),('喜劇','5'),('愛情':'13')... ...]
r_list = pattern.findall(html)
# d: {'劇情': '11', '愛情': '13', '喜劇': '5', ..., ...}
d = {}
for r in r_list:
d[r[0]] = r[1]
return d
def get_total(self, code):
"""獲取某個類別下的電影總數"""
url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(code)
html = requests.get(url=url,headers={'User-Agent':self.get_agent()}).text
html = json.loads(html)
return html['total']
if __name__ == '__main__':
spider = DoubanSpider()
spider.run()
json常用操作
import json
data = {
'name': 'pengjunlee',
'age': 32,
'vip': True,
'address': {'province': 'GuangDong', 'city': 'ShenZhen'}
}
# 將 Python 字典型別轉換為 JSON 物件
json_str = json.dumps(data)
print(json_str) # 結果 {"name": "pengjunlee", "age": 32, "vip": true, "address": {"province": "GuangDong", "city": "ShenZhen"}}
# 將 JSON 物件型別轉換為 Python 字典
user_dic = json.loads(json_str)
print(user_dic['address']) # 結果 {'province': 'GuangDong', 'city': 'ShenZhen'}
# 將 Python 字典直接輸出到檔案
with open('pengjunlee.json', 'w', encoding='utf-8') as f:
json.dump(user_dic, f, ensure_ascii=False, indent=4)
# 將類檔案物件中的JSON字串直接轉換成 Python 字典
with open('pengjunlee.json', 'r', encoding='utf-8') as f:
ret_dic = json.load(f)
print(type(ret_dic)) # 結果 <class 'dict'>
print(ret_dic['name']) # 結果 pengjunlee
json存盤串列
import json
all_app_list = [
{'name':'QQ'},
{'name':'王者榮耀'},
{'name':'和平精英'}
]
with open('xiaomi.json', 'w') as f:
json.dump(all_app_list, f, ensure_ascii=False)
CSV模板
import csv
from urllib import request, parse
import re
import time
import random
class MaoyanSpider(object):
def __init__(self):
self.url = 'https://maoyan.com/board/4?offset={}'
# 計數
self.num = 0
def get_html(self, url):
headers = {
'user-agent': 'Mozilla / 5.0(Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
}
req = request.Request(url=url, headers=headers)
res = request.urlopen(req)
html = res.read().decode('utf-8')
# 直接呼叫決議函式
self.parse_html(html)
def parse_html(self, html):
# 創建正則的編譯物件
re_ = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p> '
pattern = re.compile(re_, re.S)
# film_list:[('霸王別姬','張國榮','1993')]
film_list = pattern.findall(html)
self.write_html(film_list)
# 存入csv檔案-writerrows
def write_html(self, film_list):
L = []
with open('maoyanfilm.csv', 'a',newline='') as f:
# 初始化寫入物件,注意引數f不能忘
writer = csv.writer(f)
for film in film_list:
t = (
film[0].strip(),
film[1].strip(),
film[2].strip()[5:15]
)
self.num += 1
L.append(t)
# writerow()引數為串列
writer.writerows(L)
print(L)
def main(self):
for offset in range(0, 91, 10):
url = self.url.format(offset)
self.get_html(url)
time.sleep(random.randint(1, 2))
print('共抓取資料', self.num, "部")
if __name__ == '__main__':
start = time.time()
spider = MaoyanSpider()
spider.main()
end = time.time()
print('執行時間:%.2f' % (end - start))
txt模板
注意: 如果需要換行要自己在寫入內容中添加\n
- 單行寫入
# 以二進制方式寫入
f = open("write.txt","wb")
# 以二進制方式追加
# f = open("write.txt","ab")
# 寫入
res = f.write(b"Big Bang Bang\n")
print(res)
res = f.write(b"Big Bang Bang\n")
print(res)
#關閉
f.close()
- 多行寫入
f = open("write.txt","w")
# 寫入資訊
msg = f.writelines(["你好","我很好","那就好"])
# 關閉
f.close()
redis增量URl爬蟲實作思路

【1】原理
利用Redis集合特性,可將抓取過的指紋添加到redis集合中,根據回傳值來判定是否需要抓取
回傳值為1 : 代表之前未抓取過,需要進行抓取
回傳值為0 : 代表已經抓取過,無須再次抓取
hash加密:md5 32位、sha1 40位
創建md5物件
用update將href轉為byte型別
最后通過hexdigest獲取加密碼
【2】代碼實作模板
import redis
from hashlib import md5
import sys
class XxxIncrSpider:
def __init__(self):
self.r = redis.Redis(host='localhost',port=6379,db=0)
def url_md5(self,url):
"""對URL進行md5加密函式"""
s = md5()
s.update(url.encode())
return s.hexdigest()
def run_spider(self):
href_list = ['url1','url2','url3','url4']
for href in href_list:
href_md5 = self.url_md5(href)
if self.r.sadd('spider:urls',href_md5) == 1:
回傳值為1表示添加成功,即之前未抓取過,則開始抓取
else:
sys.exit()
休眠設定
# 控制資料抓取頻率:uniform()生成制定范圍內的浮點數
time.sleep(random.uniform(2,5))
# 生成整形的陣列
time.sleep(random.randint(1,2))
時間引數
import datetime
timestape = str(datetime.datetime.now()).split(".")[0]
打碼平臺
- 圖鑒
- 超級鷹
云詞
import os,time,json,random,jieba,requests
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from wordcloud import WordCloud
# 詞云形狀圖片
WC_MASK_IMG = 'wawa.jpg'
# 評論資料保存檔案
COMMENT_FILE_PATH = 'jd_comment.txt'
# 詞云字體
WC_FONT_PATH = '/Library/Fonts/Songti.ttc'
def spider_comment(page=0):
"""
爬取京東指定頁的評價資料
:param page: 爬取第幾,默認值為0
"""
url = 'https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv4646&productId=1263013576&score=0&sortType=5&page=%s&pageSize=10&isShadowSku=0&fold=1' % page
kv = {'user-agent': 'Mozilla/5.0', 'Referer': 'https://item.jd.com/1263013576.html'}
# proxies = {
# '1.85.5.66':'8060',
# '171.11.178.223':'9999',
# '120.194.42.157':'38185',
# '161.35.4.201':'80',
# '175.42.123.196':'9999',
# }
try:
r = requests.get(url, headers=kv)#,proxies=proxies
r.raise_for_status()
except:
print('爬取失敗')
# 截取json資料字串
r_json_str = r.text[26:-2]
# 字串轉json物件
r_json_obj = json.loads(r_json_str)
# 獲取評價串列資料
r_json_comments = r_json_obj['comments']
# 遍歷評論物件串列
for r_json_comment in r_json_comments:
# 以追加模式換行寫入每條評價
with open(COMMENT_FILE_PATH, 'a+') as file:
file.write(r_json_comment['content'] + '\n')
# 列印評論物件中的評論內容
print(r_json_comment['content'])
def batch_spider_comment():
"""
批量爬取某東評價
"""
# 寫入資料前先清空之前的資料
if os.path.exists(COMMENT_FILE_PATH):
os.remove(COMMENT_FILE_PATH)
for i in range(3):
spider_comment(i)
# 模擬用戶瀏覽,設定一個爬蟲間隔,防止ip被封
time.sleep(random.random() * 5)
def cut_word():
"""
對資料分詞
:return: 分詞后的資料
"""
with open(COMMENT_FILE_PATH) as file:
comment_txt = file.read()
wordlist = jieba.cut(comment_txt, cut_all=True)
wl = " ".join(wordlist)
print(wl)
return wl
def create_word_cloud():
"""
生成詞云
:return:
"""
# 設定詞云形狀圖片
wc_mask = np.array(Image.open(WC_MASK_IMG))
# 設定詞云的一些配置,如:字體,背景色,詞云形狀,大小
wc = WordCloud(background_color="white", max_words=2000, mask=wc_mask, scale=4,
max_font_size=50, random_state=42, font_path=WC_FONT_PATH)
# 生成詞云
wc.generate(cut_word())
# 在只設定mask的情況下,你將會得到一個擁有圖片形狀的詞云
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.figure()
plt.show()
if __name__ == '__main__':
# 爬取資料
batch_spider_comment()
# 生成詞云
create_word_cloud()
多執行緒爬蟲
應用場景
【1】多行程 :CPU密集程式
【2】多執行緒 :爬蟲(網路I/O)、本地磁盤I/O
多執行緒爬蟲示例【豆瓣】
# 抓取豆瓣電影劇情類別下的電影資訊
"""
豆瓣電影 - 劇情 - 抓取
"""
import requests
from fake_useragent import UserAgent
import time
import random
from threading import Thread,Lock
from queue import Queue
class DoubanSpider:
def __init__(self):
self.url = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start={}&limit=20'
self.i = 0
# 佇列 + 鎖
self.q = Queue()
self.lock = Lock()
def get_agent(self):
"""獲取隨機的User-Agent"""
return UserAgent().random
def url_in(self):
"""把所有要抓取的URL地址入佇列"""
for start in range(0,684,20):
url = self.url.format(start)
# url入佇列
self.q.put(url)
# 執行緒事件函式:請求+決議+資料處理
def get_html(self):
while True:
# 從佇列中獲取URL地址
# 一定要在判斷佇列是否為空 和 get() 地址 前后加鎖,防止佇列中只剩一個地址時出現重復判斷
self.lock.acquire()
if not self.q.empty():
headers = {'User-Agent': self.get_agent()}
url = self.q.get()
self.lock.release()
html = requests.get(url=url, headers=headers).json()
self.parse_html(html)
else:
# 如果佇列為空,則最終必須釋放鎖
self.lock.release()
break
def parse_html(self, html):
"""決議"""
# html: [{},{},{},{}]
item = {}
for one_film in html:
item['rank'] = one_film['rank']
item['title'] = one_film['title']
item['score'] = one_film['score']
print(item)
# 加鎖 + 釋放鎖
self.lock.acquire()
self.i += 1
self.lock.release()
def run(self):
# 先讓URL地址入佇列
self.url_in()
# 創建多個執行緒,開干吧
t_list = []
for i in range(1):
t = Thread(target=self.get_html)
t_list.append(t)
t.start()
for t in t_list:
t.join()
print('數量:',self.i)
if __name__ == '__main__':
start_time = time.time()
spider = DoubanSpider()
spider.run()
end_time = time.time()
print('執行時間:%.2f' % (end_time-start_time))
selenium+PhantomJS/Chrome/Firefox
selenium
【1】定義
1.1) 開源的Web自動化測驗工具
【2】用途
2.1) 對Web系統進行功能性測驗,版本迭代時避免重復勞動
2.2) 兼容性測驗(測驗web程式在不同作業系統和不同瀏覽器中是否運行正常)
2.3) 對web系統進行大數量測驗
【3】特點
3.1) 可根據指令操控瀏覽器
3.2) 只是工具,必須與第三方瀏覽器結合使用
【4】安裝
4.1) Linux: sudo pip3 install selenium
4.2) Windows: python -m pip install selenium
繞過selenium檢測
from selenium import webdriver
options = webdriver.ChromeOptions()
# 此步驟很重要,設定為開發者模式,防止被各大網站識別出來使用了Selenium
options.add_experimental_option('excludeSwitches', ['enable-automation'])
#停止加載圖片
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
browser = webdriver.Chrome(options=options)
browser.get('https://www.taobao.com/')
selenium對cookie的處理
selenium能夠幫助我們處理頁面中的cookie,比如獲取、洗掉,接下來我們就學習這部分知識
獲取cookie
driver.get_cookies()回傳串列,其中包含的是完整的cookie資訊!不光有name、value,還有domain等cookie其他維度的資訊,所以如果想要把獲取的cookie資訊和requests模塊配合使用的話,需要轉換為name、value作為鍵值對的cookie字典
# 獲取當前標簽頁的全部cookie資訊
print(driver.get_cookies())
# 把cookie轉化為字典
cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()}
洗掉cookie
#洗掉一條cookie
driver.delete_cookie("CookieName")
# 洗掉所有的cookie
driver.delete_all_cookies()
selenium使用代理ip
selenium控制瀏覽器也是可以使用代理ip的!
-
使用代理ip的方法
- 實體化配置物件
options = webdriver.ChromeOptions()
- 配置物件添加使用代理ip的命令
options.add_argument('--proxy-server=http://202.20.16.82:9527')
- 實體化帶有配置物件的driver物件
driver = webdriver.Chrome('./chromedriver', chrome_options=options)
- 實體化配置物件
-
參考代碼如下:
from selenium import webdriver options = webdriver.ChromeOptions() # 創建一個配置物件 options.add_argument('--proxy-server=http://202.20.16.82:9527') # 使用代理ip driver = webdriver.Chrome(chrome_options=options) # 實體化帶有配置的driver物件 driver.get('http://www.itcast.cn') print(driver.title) driver.quit()
selenium替換user-agent
selenium控制谷歌瀏覽器時,User-Agent默認是谷歌瀏覽器的,這一小節我們就來學習使用不同的User-Agent
-
替換user-agent的方法
- 實體化配置物件
options = webdriver.ChromeOptions()
- 配置物件添加替換UA的命令
options.add_argument('--user-agent=Mozilla/5.0 HAHA')
- 實體化帶有配置物件的driver物件
driver = webdriver.Chrome('./chromedriver', chrome_options=options)
- 實體化配置物件
-
參考代碼如下:
from selenium import webdriver options = webdriver.ChromeOptions() # 創建一個配置物件 options.add_argument('--user-agent=Mozilla/5.0 HAHA') # 替換User-Agent driver = webdriver.Chrome('./chromedriver', chrome_options=options) driver.get('http://www.itcast.cn') print(driver.title) driver.quit()
- selenium替換user-agent
指定埠遙控
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('debuggerAddress','127.0.0.1:9222')
browser=webdriver.Chrome(executable_path=r'C:\Users\TR\AppData\Local\Google\Chrome
\Application\chromedriver.exe',chrome_options=chrome_options)
browser.get('http://www.zhihu.com')
PhantomJS瀏覽器
【1】定義
phantomjs為無界面瀏覽器(又稱無頭瀏覽器),在記憶體中進行頁面加載,高效
【2】下載地址
2.1) chromedriver : 下載對應版本
http://npm.taobao.org/mirrors/chromedriver/
2.2) geckodriver
https://github.com/mozilla/geckodriver/releases
2.3) phantomjs
https://phantomjs.org/download.html
【3】Ubuntu安裝
3.1) 下載后解壓 : tar -zxvf geckodriver.tar.gz
3.2) 拷貝解壓后檔案到 /usr/bin/ (添加環境變數)
sudo cp geckodriver /usr/bin/
3.3) 添加可執行權限
sudo chmod 777 /usr/bin/geckodriver
【4】Windows安裝
4.1) 下載對應版本的phantomjs、chromedriver、geckodriver
4.2) 把chromedriver.exe拷貝到python安裝目錄的Scripts目錄下(添加到系統環境變數)
# 查看python安裝路徑: where python
4.3) 驗證
cmd命令列: chromedriver
***************************總結**************************************
【1】解壓 - 放到用戶主目錄(chromedriver、geckodriver、phantomjs)
【2】拷貝 - sudo cp /home/tarena/chromedriver /usr/bin/
【3】權限 - sudo chmod 777 /usr/bin/chromedriver
# 驗證
【Ubuntu | Windows】
ipython3
from selenium import webdriver
webdriver.Chrome()
或者
webdriver.Firefox()
【mac】
ipython3
from selenium import webdriver
webdriver.Chrome(executable_path='/Users/xxx/chromedriver')
或者
webdriver.Firefox(executable_path='/User/xxx/geckodriver')
百度示例代碼
"""示例代碼一:使用 selenium+瀏覽器 打開百度"""
# 匯入seleinum的webdriver介面
from selenium import webdriver
import time
# 創建瀏覽器物件
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
# 5秒鐘后關閉瀏覽器
time.sleep(5)
browser.quit()
"""示例代碼二:打開百度,搜索趙麗穎,點擊搜索,查看"""
from selenium import webdriver
import time
# 1.創建瀏覽器物件 - 已經打開了瀏覽器
browser = webdriver.Chrome()
# 2.輸入: http://www.baidu.com/
browser.get('http://www.baidu.com/')
# 3.找到搜索框,向這個節點發送文字: 趙麗穎
browser.find_element_by_xpath('//*[@id="kw"]').send_keys('趙麗穎')
# 4.找到 百度一下 按鈕,點擊一下
browser.find_element_by_xpath('//*[@id="su"]').click()
瀏覽器物件(browser)方法
【1】browser.get(url=url) - 地址欄輸入url地址并確認
【2】browser.quit() - 關閉瀏覽器
【3】browser.close() - 關閉當前頁
【4】browser.page_source - HTML結構原始碼
【5】browser.page_source.find('字串')
從html原始碼中搜索指定字串,沒有找到回傳:-1,經常用于判斷是否為最后一頁
【6】browser.maximize_window() - 瀏覽器視窗最大化
Selenium 定位節點八種方法
【1】單元素查找('結果為1個節點物件')
1.1) 【最常用】browser.find_element_by_id('id屬性值')
1.2) 【最常用】browser.find_element_by_name('name屬性值')
1.3) 【最常用】browser.find_element_by_class_name('class屬性值')
1.4) 【最萬能】browser.find_element_by_xpath('xpath運算式')
1.5) 【匹配a節點時常用】browser.find_element_by_link_text('鏈接文本')
1.6) 【匹配a節點時常用】browser.find_element_by_partical_link_text('部分鏈接文本')
1.7) 【最沒用】browser.find_element_by_tag_name('標記名稱')
1.8) 【較常用】browser.find_element_by_css_selector('css運算式')
【2】多元素查找('結果為[節點物件串列]')
2.1) browser.find_elements_by_id('id屬性值')
2.2) browser.find_elements_by_name('name屬性值')
2.3) browser.find_elements_by_class_name('class屬性值')
2.4) browser.find_elements_by_xpath('xpath運算式')
2.5) browser.find_elements_by_link_text('鏈接文本')
2.6) browser.find_elements_by_partical_link_text('部分鏈接文本')
2.7) browser.find_elements_by_tag_name('標記名稱')
2.8) browser.find_elements_by_css_selector('css運算式')
貓眼電影示例
from selenium import webdriver
import time
url = 'https://maoyan.com/board/4'
browser = webdriver.Chrome()
browser.get(url)
def get_data():
# 基準xpath: [<selenium xxx li at xxx>,<selenium xxx li at>]
li_list = browser.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd')
for li in li_list:
item = {}
# info_list: ['1', '霸王別姬', '主演:張國榮', '上映時間:1993-01-01', '9.5']
info_list = li.text.split('\n')
item['number'] = info_list[0]
item['name'] = info_list[1]
item['star'] = info_list[2]
item['time'] = info_list[3]
item['score'] = info_list[4]
print(item)
while True:
get_data()
try:
browser.find_element_by_link_text('下一頁').click()
time.sleep(2)
except Exception as e:
print('恭喜你!抓取結束')
browser.quit()
break
-
節點物件操作
【1】文本框操作 1.1) node.send_keys('') - 向文本框發送內容 1.2) node.clear() - 清空文本 1.3) node.get_attribute('value') - 獲取文本內容 【2】按鈕操作 1.1) node.click() - 點擊 1.2) node.is_enabled() - 判斷按鈕是否可用 1.3) node.get_attribute('value') - 獲取按鈕文本
chromedriver設定無界面模式
from selenium import webdriver
options = webdriver.ChromeOptions()
# 添加無界面引數
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)
selenium - 滑鼠操作
from selenium import webdriver
# 匯入滑鼠事件類
from selenium.webdriver import ActionChains
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
# 移動到 設定,perform()是真正執行操作,必須有
element = driver.find_element_by_xpath('//*[@id="u1"]/a[8]')
ActionChains(driver).move_to_element(element).perform()
# 單擊,彈出的Ajax元素,根據鏈接節點的文本內容查找
driver.find_element_by_link_text('高級搜索').click()
selenium處理iframe反爬
- 經典案例 民政局抓取、QQ郵箱登錄、163郵箱登錄
【1】滑鼠操作
from selenium.webdriver import ActionChains
ActionChains(browser).move_to_element(node).perform()
【2】切換句柄
all_handles = browser.window_handles
time.sleep(1)
browser.switch_to.window(all_handles[1])
【3】iframe子框架
browser.switch_to.frame(iframe_element)
# 寫法1 - 任何場景都可以:
iframe_node = browser.find_element_by_xpath('')
browser.switch_to.frame(iframe_node)
# 寫法2 - 默認支持 id 和 name 兩個屬性值:
browser.switch_to.frame('id屬性值|name屬性值')
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/280698.html
標籤:python
上一篇:爬蟲實戰5:爬取全部穿越火線武器的圖片以武器名稱命名保存到本地檔案
下一篇:第一次Python接單的程序記錄
