大师兄的Python学习笔记(二十四): 爬虫(五)

2020-08-05  本文已影响0人  superkmi

大师兄的Python学习笔记(二十三): 爬虫(四)
大师兄的Python学习笔记(二十五): 爬虫(六)

六、模拟浏览器爬取动态数据

1. 使用Selenium
1.1 配置工作
1.2 控制浏览器
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>print(type(browser))
<class 'selenium.webdriver.firefox.webdriver.WebDriver'>
1.3 访问网页
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
1.4 点击浏览器功能键
方法 按键
browser.back() 返回键
browser.forward() 前进键
browser.refresh() 刷新键
browser.quit() 关闭窗口
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>browser.quit()
1.5 元素定位
属性 方法
name定位 find_element_by_name()
id定位 find_element_by_id()
class定位 find_element_by_class_name()
tag定位 find_element_by_tag_name()
link定位 find_element_by_link_text()
link模糊定位 find_element_by_partial_link_text()
css选择器定位 find_element_by_css_selector()
xpath定位 find_element_by_xpath()
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.jd.com/")
>>>elem = browser.find_element_by_class_name('jd_container')
>>>print(elem)
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="de178311-9772-4548-be2c-702c03d2c003", element="95a16302-1bc4-46f6-b94b-228ed1e5e34b")>
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.jd.com/")
>>>elem = browser.find_element(By.CLASS_NAME,'jd_container')
>>>print(elem)
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="2b0f839f-a3d2-41ac-ab6b-4de00fefbd3e", element="d6fc8532-f69d-431b-8415-47c7b5ad82ce")>
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.jd.com/")
>>>elems = browser.find_elements(By.TAG_NAME,'div')
>>>print(len(elems))
453
1.6 元素操作

1) 输入文字

  • 使用send_key()方法输入文字。
  • 使用clear()方法清空文字。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>input = browser.find_element(By.CSS_SELECTOR,'.s_ipt')
>>>input.send_keys('天问')

2) 提交表单
  • 使用submit()方法提交表单。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>input = browser.find_element(By.CSS_SELECTOR,'.s_ipt')
>>>input.send_keys('天问')
>>>input.submit()

3) 左键点击页面
  • 使用click()方法实现左键点击。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>input = browser.find_element(By.CSS_SELECTOR,'.s_ipt') # 找到搜索栏
>>>submit = browser.find_element(By.ID,'su') # 找到submit按键
>>>input.send_keys('天问')
>>>submit.submit()

4) 发送特殊键
  • 对于一些不能用字符串值输入的键,用selenium.webdriver.common.keys模块的属性表示。
属性
Keys.Down, Keys.UP, Keys.LEFT, Keys.RIGHT 键盘箭头键
Keys.ENTER, Keys.RETURN 回车和换行键
Keys.HOME, Keys.END, Keys.PAGE_DOWN, Keys.PAGE_UP 小键盘home,end,down,up
Keys.ESCAPE, Keys.BACK_SPACE, Keys.DELETE Esc, Backspace和Delete键
Keys.F1 - Keys.F12 F1-F12键
Keys.TAB tab键
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By
>>>from selenium.webdriver.common.keys import Keys

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>input = browser.find_element(By.CSS_SELECTOR,'.s_ipt') # 找到搜索栏
>>>input.send_keys('天问')
>>>input.send_keys(Keys.BACK_SPACE) # 按一下backspace
1.7 动作链
方法 动作
click(on_element=None) 左键单击元素或当前位置
click_and_hold(on_element=None) 左键按住元素或当前位置
context_click(on_element=None) 右键单击元素或当前位置
double_click(on_element=None) 左键双击元素或当前位置
drag_and_drop(source, target) 拖拽元素到元素
drag_and_drop_by_offset(source, xoffset, yoffset) 拖拽元素到坐标
key_down(value, element=None) 按下某个键
key_up(value, element=None) 松开某个键
move_by_offset(xoffset, yoffset) 移动鼠标到坐标
move_to_element(to_element) 移动鼠标到元素
move_to_element_with_offset(to_element, xoffset, yoffset) 移动鼠标经过坐标到元素
pause(seconds) 暂停动作?秒
perform() 执行所有设置的动作
release(on_element=None) 抬起鼠标键
reset_actions() 清除已存储的动作
send_keys(*keys_to_send) 输入按键到当前元素
send_keys_to_element(element, *keys_to_send) 输入按键到指定元素
>>>from selenium import webdriver
>>>from selenium.webdriver import ActionChains

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>elem = browser.find_element_by_tag_name('div')
>>>actions = ActionChains(browser)
>>>actions.context_click(elem)
>>>actions.perform()
1.8 执行页面JS
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>browser.execute_script('alert("Hi there!")')
1.9 获取元素的信息

1) 获取属性

  • 使用get_attribute(name)方法获取元素属性。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>input = browser.find_element(By.CSS_SELECTOR,'.s_ipt') # 找到搜索栏
>>>print(input.get_attribute('class'))
s_ipt

2) 获取文本内容

  • 使用text属性获取文本内容。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>elem = browser.find_element(By.CLASS_NAME,'title-content-title') # 找到搜索栏
>>>print(elem.text)
31省区市新增确诊101例

3) 获取其他属性

  • 可以使用id、location、tag_name、size获得对应属性。
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com/")
>>>elem = browser.find_element(By.CLASS_NAME,'title-content-title') # 找到搜索栏
>>>print(elem.id)
>>>print(elem.location)
>>>print(elem.tag_name)
>>>print(elem.size)
08152d64-0910-4d13-a779-d1413f215305
{'x': 343, 'y': 364}
span
{'height': 16.0, 'width': 152.0}
1.10 切换frame
>>>from selenium import webdriver
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")
>>>browser.switch_to.frame('iframeResult')
>>>print(browser.find_element_by_tag_name('div').id)
f22025d4-e23a-4fc8-b762-7afad154e487
1.11 延时操作

1) implicity_wait(time_to_wait=0) 隐式等待

  • 设置一个全局的等待时间,如果页面加载超过等待时间将报错。
>>>from selenium import webdriver
>>>from selenium.common.exceptions import NoSuchElementException

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>browser.implicitly_wait(5)
>>>try:
>>>    elem = browser.find_element_by_tag_name("not exist")
>>>except NoSuchElementException as e:
>>>    print(e)
Message: Unable to locate element: not exist

2) WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) 显式等待

  • 设定一个等待时间,如果指定元素加载时间超过等待时间将报错。
>>>from selenium import webdriver
>>>from selenium.common.exceptions import TimeoutException
>>>from selenium.webdriver.support.ui import WebDriverWait
>>>from selenium.webdriver.support import expected_conditions as EC
>>>from selenium.webdriver.common.by import By

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>wait = WebDriverWait(browser, 5)
>>>try:
>>>    elem = wait.until(EC.presence_of_element_located((By.CLASS_NAME,'not exist')))
>>>except TimeoutException as e:
>>>    print(e)
Message: 

3) time.sleep()

  • 当然也可以使用time.sleep(), 只是在等待时程序会被阻塞。
1.12 操作Cookies

1) 获取Cookies

  • 使用get_cookies()方法获取cookies。
  • 使用get_cookie(name)方法获取指定cookie。
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>print(browser.get_cookies())
[{'name': 'BIDUPSID', 'value': 'BE5178FF29CB21C49CF5B5F9EBA5A178', 'path': '/', 'domain': '.baidu.com', 'secure': False, 'httpOnly': False, 'expiry': 3743553861}, {'name': 'PSTM', 'value': '1596070212', 'path': '/', 'domain': '.baidu.com', 'secure': False, 'httpOnly': False, 'expiry': 3743553861}, {'name': 'BAIDUID', 'value': 'BE5178FF29CB21C4CDCEFB0448819390:FG=1', 'path': '/', 'domain': '.baidu.com', 'secure': False, 'httpOnly': False, 'expiry': 1627606214}, {'name': 'BD_HOME', 'value': '1', 'path': '/', 'domain': 'www.baidu.com', 'secure': False, 'httpOnly': False}, {'name': 'H_PS_PSSID', 'value': '32294_1434_31670_32141_32045_32395_32429_32115_32436_32261', 'path': '/', 'domain': '.baidu.com', 'secure': False, 'httpOnly': False}, {'name': 'BD_UPN', 'value': '13314752', 'path': '/', 'domain': 'www.baidu.com', 'secure': False, 'httpOnly': False, 'expiry': 1596934215}]

2) 增加Cookies

  • 使用add_cookie()方法添加Cookie。
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>cookie = {
>>>    'name':'name',
>>>    'domain':'www.baidu.com',
>>>    'value':'superkmi'
>>>}
>>>browser.add_cookie(cookie)
>>>print(browser.get_cookie('name'))
{'name': 'name', 'value': 'superkmi', 'path': '/', 'domain': '.www.baidu.com', 'secure': False, 'httpOnly': False}

3) 删除Cookies

  • 使用delete_all_cookies()方法删除所有cookies。
  • 使用delete_cookie(name)方法删除指定cookie。
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>browser.delete_all_cookies()
>>>print(browser.get_cookies())
[]
1.13 切换选项卡
>>>from selenium import webdriver

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>browser.get("https://www.baidu.com")
>>>browser.execute_script("window.open()") # 打开一个新的选项卡
>>>browser.switch_to.window(browser.window_handles[1]) # 切换到第二个选项卡
>>>browser.get("https://www.sina.com.cn")
1.14 异常处理
>>>from selenium import webdriver
>>>from selenium.common.exceptions import InvalidArgumentException

>>>browser = webdriver.Firefox() # 获得火狐浏览器的模拟对象
>>>try:
>>>    browser.get("not exist")
>>>except InvalidArgumentException as e:
>>>    print(e.msg)
>>>Malformed URL: not exist is not a valid URL.
1.15 爬取京东商品案例
>>>from selenium import webdriver
>>>from selenium.webdriver import ActionChains
>>>from selenium.webdriver.common.by import By
>>>from selenium.webdriver.common.keys import Keys
>>>from selenium.webdriver.support import expected_conditions as EC
>>>from selenium.webdriver.support.wait import WebDriverWait
>>>from selenium.common.exceptions import *
>>>from urllib import parse
>>>from pyquery import PyQuery as pq

>>>class jd_spider_sample():
>>>    def __init__(self,kw,wait_time=10,page_num=1,target_page=10):
>>>        self.url = "https://search.jd.com/Search?keyword="+parse.quote(kw)
>>>        self.cur_page_num = page_num
>>>        self.target_page = target_page
>>>        self.browser = webdriver.Firefox()
>>>        self.browser.implicitly_wait(wait_time)
>>>        self.wait = WebDriverWait(self.browser,wait_time)
>>>        self.products = []
>>>        self.get_pages()

>>>    def get_pages(self):
>>>        # 遍历搜索页面
>>>        try:
>>>            self.browser.get(self.url)
>>>            # 模拟翻页
>>>            while self.cur_page_num < self.target_page:
>>>                self.wait.until_not(
>>>                    EC.presence_of_element_located((By.CSS_SELECTOR, '.loading-style1'))) # 等loading标签消失
>>>                actions = ActionChains(self.browser)
>>>                actions.send_keys(Keys.RIGHT) # 京东按右键就可以翻页
>>>                actions.perform()
>>>                self.get_page_data(self.browser.page_source) # 获取页面html代码
>>>                self.cur_page_num += 1
>>>        except TimeoutException as e:
>>>            print(e.msg)

>>>    def get_page_data(self,page):
>>>        # 解析html代码
>>>        data = pq(page)
>>>        items = data('.gl-item-presell .gl-i-wrap').items()
>>>        for item in items:
>>>            product = {
>>>                'name':item.find('.p-name em').text().replace('\n',''),
>>>                'price': float(item.find('.p-price i').text()),
>>>                'score':float(item.find('.buy-score>em').text()) if item.find('.buy-score>em').text() else 0,
>>>                'comment':item.find('.p-commit a').text(),
>>>                'shop':item.find('.p-shop a').text(),
>>>                'img': item.find('.p-img a img').attr('src'),
>>>                'link': item.find('.p-img>a').attr('href')
>>>            }
>>>            self.products.append(product)

>>>    def show_result(self):
>>>        # 按价格和评分排序后打印
>>>        result = self.products
>>>        result.sort(key=lambda k:(k.get("price"),k.get("score")),reverse=True) # 重新排序
>>>        for i,data in enumerate(result):
>>>            print(f"{i+1}. {data.get('name')} \n价格:{data.get('price')}元 \n评分:{data.get('score')} \n网店:{data.get('shop')} "
>>>                  f"\n评论数:{data.get('comment')} \n图片:{data.get('img')} \n链接:{data.get('link')}\n")

>>>if __name__ == '__main__':
>>>    spider = jd_spider_sample("电视",page_num=1)
>>>    spider.show_result()
1. 线下同款 索尼(SONY)KD-75X9500H 75英寸 4K超高清 HDR 液晶平板电视全面屏 X1旗舰版图像芯片 全阵列背光 
价格:18999.0元 
评分:10.0 
网店:SONY京东自营官方旗舰店 
评论数:1.3万+ 
图片://img13.360buyimg.com/n7/jfs/t1/84754/28/18878/271674/5e97d93bE4e2687ed/87c81d5a826be8fe.jpg 
链接://item.jd.com/100006893993.html

2. 线下同款 索尼(SONY)KD-85X9000H 85英寸 4K HDR超高清液晶电视X1图像芯片 专业游戏模式 AI智能语音 安卓9.0 
价格:18999.0元 
评分:0 
网店:SONY京东自营官方旗舰店 
评论数:3300+ 
图片://img10.360buyimg.com/n7/jfs/t1/116422/5/5653/255413/5eb4f436Ed44fd99a/c16b76f7607ee776.jpg 
链接://item.jd.com/100013149730.html

3. 京品家电 索尼(SONY)京品家电 KD-75X9100H 75英寸 4K超高清 全面屏AI智能电视X1图像芯片 专业游戏 4K 120帧输入 
价格:13499.0元 
评分:9.2 
网店:SONY京东自营官方旗舰店 
评论数:1.3万+ 
图片://img12.360buyimg.com/n7/jfs/t1/139273/34/1300/327463/5ef17810E06b3f939/7746df18780abb9f.jpg 
链接://item.jd.com/100007346967.html

4. 海信(Hisense)85E7F 85英寸4K超高清 超薄全面屏 AI语音 液晶海信电视机 
价格:12999.0元 
评分:0 
网店:海信电视旗舰店 
评论数:70+ 
图片://img10.360buyimg.com/n7/jfs/t1/135769/10/5756/221595/5f2372b0Ebb8d3bdb/29c4052cfdf9b922.jpg 
链接://item.jd.com/67420158670.html

5. 线下同款 索尼(SONY)KD-65X9500H 65英寸 4K超高清 HDR 液晶平板电视全面屏 X1旗舰版图像芯片 
价格:10999.0元 
评分:5.9 
网店:SONY京东自营官方旗舰店 
评论数:4.3万+ 
图片://img13.360buyimg.com/n7/jfs/t1/121400/2/1594/291493/5ebe0db6E80c2591d/db85a5f81c219fc3.jpg 
链接://item.jd.com/100013299648.html

6. 线下同款 索尼(SONY)KD-75X8000H 75英寸 4K超高清 HDR 液晶平板电视智能家居 安卓9.0系统 
价格:8699.0元 
评分:9.2 
网店:SONY京东自营官方旗舰店 
评论数:1.3万+ 
图片://img14.360buyimg.com/n7/jfs/t1/144869/17/2804/353725/5f0bd9d5E4f38befc/d556a3325dadce46.jpg 
链接://item.jd.com/100012583754.html

7. 海信(Hisense)75E7F 75英寸 4K 2+32GB AI声控 MEMC防抖 超薄悬浮全面屏 超高色域 教育 液晶电视机 
价格:8599.0元 
评分:10.0 
网店:海信京东自营旗舰店 
评论数:3万+ 
图片://img14.360buyimg.com/n7/jfs/t1/130726/16/5262/154818/5f1abefdEf302bbf7/e6d18b6db90936e4.jpg 
链接://item.jd.com/100011529794.html

8. 线下同款 三星(SAMSUNG)65英寸Q70 QLED量子点 4K超高清 全阵列背光 HDR 教育资源液晶电视QA65Q70RAJXXZ 线下同款 
价格:8589.0元 
评分:10.0 
网店:三星家电京东自营旗舰店 
评论数:4.3万+ 
图片://img11.360buyimg.com/n7/jfs/t1/142358/13/2904/177046/5f0ea27fE9b39fa10/61c51ad9001a5f1d.jpg 
链接://item.jd.com/100003314751.html

9. 线下同款 索尼(SONY)KD-55X9500H 55英寸 4K超高清 HDR 液晶平板电视全面屏 X1旗舰版图像芯片 全阵列背光 
价格:6999.0元 
评分:9.9 
网店:SONY京东自营官方旗舰店 
评论数:7万+ 
图片://img11.360buyimg.com/n7/jfs/t1/110787/25/4063/271674/5e97d57bEf3e65721/21607ee25e95d4bd.jpg 
链接://item.jd.com/100006893991.html

10. 创维(SKYWORTH)65J9000 65英寸 4K超高清 智慧屏 防蓝光护眼 远场语音 超薄全面屏 教育电视2+32G内存 
价格:6999.0元 
评分:9.1 
网店:创维电视京东自营旗舰店 
评论数:2500+ 
图片://img11.360buyimg.com/n7/jfs/t1/142757/39/3939/146459/5f200f26Ee4e71929/b906384ce1e135a5.jpg 
链接://item.jd.com/100006423611.html
... ...
2. 使用Splash
2.1 实现功能
2.2 安装和配置
2.3 使用Python获取渲染页面

1) render.html

  • 用于获取JavaScript渲染页面的HTML代码。
  • 可以使用的参数:
参数 是否必选 类型 描述
url 必选 string 需要渲染页面的url
timeout 可选 float 渲染页面超时时间
proxy 可选 string 代理服务器地址
wait 可选 float 等待页面渲染的时间
images 可选 integer 是否下载图片,默认为1
js_source 可选 string 用户自定义JavaScript代码,在页面渲染前执行
>>>import requests
>>>url = 'http://localhost:8050/render.html?wait=0.5&timeout=90.0&url=https://www.baidu.com'
>>>response = requests.get(url)
>>>print(response.status_code)
200

2) render.png

  • 获得网页截图。
  • 通过width和height参数指定截图的宽和高。
  • 返回二进制图片数据。
>>>import requests
>>>import os
>>>url = 'http://localhost:8050/render.png?wait=0.5&timeout=90.0&url=https://www.baidu.com&width1024&768'
>>>response = requests.get(url)
>>>with open("sample.png","wb") as f:
>>>    f.write(response.content)
>>>os.system("sample.png")

3) render.jpeg
  • render.png类似,但返回的是jpeg图片。
  • 增加了参数quality,用来设置图片质量。
>>>import requests
>>>url = 'http://localhost:8050/render.jpeg?wait=0.5&timeout=90.0&quality=75&url=https://www.baidu.com&width1024&768'
>>>response = requests.get(url)
>>>print(response.status_code)
200

4) render.HAR

  • 获取页面加载的HAR数据。
>>>import requests
>>>from pprint import pprint
>>>url = 'http://localhost:8050/render.har?wait=0.5&timeout=90.0&url=https://www.baidu.com&width1024&768'
>>>response = requests.get(url)
>>>pprint(response.text)
('{"log": {"version": "1.2", "creator": {"name": "Splash", "version": '
'"3.4.1"}, "browser": {"name": "QWebKit", "version": "602.1", "comment": '
'"PyQt 5.13.1, Qt 5.13.1"}, "entries": [{"_splash_processing_state": '
'"finished", "startedDateTime": "2020-08-05T01:26:33.874870Z", "request": '
'{"method": "GET", "url": "https://www.baidu.com/", "httpVersion": '
'"HTTP/1.1", "cookies": [], "queryString": [], "headers": [{"name": '
... ...

5) render.json

  • 以json格式返回相应的请求数据。
>>>import requests
>>>from pprint import pprint
>>>url = 'http://localhost:8050/render.json?>>>>wait=0.5&timeout=90.0&url=https://www.baidu.com&width1024&768'
>>>response = requests.get(url)
>>>pprint(response.text)
('{"url": "https://www.baidu.com/", "requestedUrl": "https://www.baidu.com/", '
'"geometry": [0, 0, 1024, 768], "title": '
'"\\u767e\\u5ea6\\u4e00\\u4e0b\\uff0c\\u4f60\\u5c31\\u77e5\\u9053"}')

6) execute

  • 用于执行LUA脚本。
>>>import requests
>>>from urllib.parse import quote
>>>lua_code = '''
>>>    function main(splash)
>>>        return 'Hello World!'
>>>    end
>>>'''
>>>url = 'http://localhost:8050/execute?lua_source='+quote(lua_code)
>>>response = requests.get(url)
>>>print(response.text)
Hello World!

参考资料



本文作者:大师兄(superkmi)

上一篇下一篇

猜你喜欢

热点阅读