精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

使用NodeJS請求抓取帶有進程Cookie認證的站點

譯文 精選
開發(fā)
使用NodeJS流抓取數(shù)據(jù)并將其寫入文件

  作者 | Lokesh Joshi

  譯者 | 張哲剛

  審校丨Noe

簡介

  當前,NodeJS擁有大量的庫,基本上可以解決所有的常規(guī)需求。網(wǎng)絡(luò)抓取是一項門檻較低的技術(shù),衍生了大量自由職業(yè)者以及開發(fā)團隊。自然而然,NodeJS的庫生態(tài)系統(tǒng)幾乎包含了網(wǎng)絡(luò)解析所需的一切。

  本文論述中,首先假定已經(jīng)運行在應(yīng)用程序皆為NodeJS解析而工作的核心設(shè)備之上。此外,我們將研究一個示例,從銷售品牌服裝和飾品的網(wǎng)站https://outlet.scotch-soda.com 站點中的幾百個頁面里收集數(shù)據(jù)。這些代碼示例類似于一些真實的抓取應(yīng)用程序,其中一個就是在Yelp抓取中使用。

  當然,由于本文研究所限,示例中刪除了一些生產(chǎn)組件,例如數(shù)據(jù)庫、容器化、代理連接以及進程管理工具(例如pm2)。另外,在諸如linting這類顯而易見的事務(wù)上也不會停止。

  但是,我們會保證項目的基本結(jié)構(gòu)完善,將使用最流行的庫(Axios,Cheerio,Lodash),使用Puppeter提取授權(quán)密鑰,使用NodeJS流抓取數(shù)據(jù)并將其寫入文件。

術(shù)語規(guī)定

  本文將使用以下術(shù)語:NodeJS應(yīng)用程序——服務(wù)器應(yīng)用程序;網(wǎng)站 outlet.scotch-soda.com ——Web資源,網(wǎng)站服務(wù)器為Web服務(wù)器。大體來說,首先是在Chrome或Firefox中探究網(wǎng)站網(wǎng)絡(luò)資源及其頁面,然后運行一個服務(wù)器應(yīng)用程序,向Web服務(wù)器發(fā)送HTTP請求,最后收到帶有相應(yīng)數(shù)據(jù)的響應(yīng)。

獲取授權(quán)Cookie

  outlet.scotch-soda.com的內(nèi)容僅對授權(quán)用戶開放。本示例中,授權(quán)將通過由服務(wù)器應(yīng)用程序控制的Chromium瀏覽器實施,cookie也是從其中接收。這些Cookie將包含在每個向web服務(wù)器發(fā)出的HTTP請求上的HTTP標頭中,從而允許應(yīng)用程序訪問這些授權(quán)內(nèi)容。當抓取具有數(shù)萬乃至數(shù)十萬頁面的大量資源時,接收到的Cookie需要更新一些次數(shù)。

  該應(yīng)用程序?qū)⒕哂幸韵陆Y(jié)構(gòu):

  cookieManager.js:帶有Cookie管理器類的文件,用以負責獲取cookie;

  cookie-storage.js: cookie 變量文件;

  index.js:安排Cookie管理器調(diào)用點;

  .env:環(huán)境變量文件。

  /project_root

  |__ /src

  |   |__ /helpers

  |      |__ **cookie-manager.js**

  |      |__ **cookie-storage.js**

  |**__ .env**

  |__ **index.js**

  主目錄和文件結(jié)構(gòu)

  將以下代碼添加到應(yīng)用程序中:

// index.js

// including environment variables in .env
require('dotenv').config();

const cookieManager = require('./src/helpers/cookie-manager');
const { setLocalCookie } = require('./src/helpers/cookie-storage');

// IIFE - application entry point
(async () => {
// CookieManager call point
// login/password values are stored in the .env file
const cookie = await cookieManager.fetchCookie(
process.env.LOGIN,
process.env.PASSWORD,
);

if (cookie) {
// if the cookie was received, assign it as the value of a storage variable
setLocalCookie(cookie);
} else {
console.log('Warning! Could not fetch the Cookie after 3 attempts. Aborting the process...');
// close the application with an error if it is impossible to receive the cookie
process.exit(1);
}
})();

  在cookie-manager.js中:

// cookie-manager.js

// 'user-agents' generates 'User-Agent' values for HTTP headers
// 'puppeteer-extra' - wrapper for 'puppeteer' library
const _ = require('lodash');
const UserAgent = require('user-agents');
const puppeteerXtra = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

// hide from webserver that it is bot
puppeteerXtra.use(StealthPlugin());

class CookieManager {
// this.browser & this.page - Chromium window and page instances
constructor() {
this.browser = null;
this.page = null;
this.cookie = null;
}

// getter
getCookie() {
return this.cookie;
}

// setter
setCookie(cookie) {
this.cookie = cookie;
}

async fetchCookie(username, password) {
// give 3 attempts to authorize and receive cookies
const attemptCount = 3;

try {
// instantiate Chromium window and blank page
this.browser = await puppeteerXtra.launch({
args: ['--window-size=1920,1080'],
headless: process.env.NODE_ENV === 'PROD',
});

// Chromium instantiates blank page and sets 'User-Agent' header
this.page = await this.browser.newPage();
await this.page.setUserAgent((new UserAgent()).toString());

for (let i = 0; i < attemptCount; i += 1) {
// Chromium asks the web server for an authorization page
//and waiting for DOM
await this.page.goto(process.env.LOGIN_PAGE, { waitUntil: ['domcontentloaded'] });

// Chromium waits and presses the country selection confirmation button
// and falling asleep for 1 second: page.waitForTimeout(1000)
await this.page.waitForSelector('#changeRegionAndLanguageBtn', { timeout: 5000 });
await this.page.click('#changeRegionAndLanguageBtn');
await this.page.waitForTimeout(1000);

// Chromium waits for a block to enter a username and password
await this.page.waitForSelector('div.login-box-content', { timeout: 5000 });
await this.page.waitForTimeout(1000);

// Chromium enters username/password and clicks on the 'Log in' button
await this.page.type('input.email-input', username);
await this.page.waitForTimeout(1000);
await this.page.type('input.password-input', password);
await this.page.waitForTimeout(1000);
await this.page.click('button[value="Log in"]');
await this.page.waitForTimeout(3000);

// Chromium waits for target content to load on 'div.main' selector
await this.page.waitForSelector('div.main', { timeout: 5000 });

// get the cookies and glue them into a string of the form <key>=<value> [; <key>=<value>]
this.setCookie(
_.join(
_.map(
await this.page.cookies(),
({ name, value }) => _.join([name, value], '='),
),
'; ',
),
);

// when the cookie has been received, break the loop
if (this.cookie) break;
}

// return cookie to call point (in index.js)
return this.getCookie();
} catch (err) {
throw new Error(err);
} finally {
// close page and browser instances
this.page && await this.page.close();
this.browser && await this.browser.close();
}
}
}

// export singleton
module.exports = new CookieManager();

  某些變量的值是鏈接到.env文件的。

  // .env

  NODE_ENV=DEV

  LOGIN_PAGE=https://outlet.scotch-soda.com/de/en/login

  LOGIN=tyrell.wellick@ecorp.com

  PASSWORD=i*m_on@kde

  例如,配置無頭消息屬性,發(fā)送到方法 puppeteerXtra.launch解析為布爾值,它取決于狀態(tài)可變的process.env.node_env 。在開發(fā)過程中,變量被設(shè)置為DEV,無頭變量被設(shè)置為false,因此Puppeteer能夠明白它此刻應(yīng)該在監(jiān)視器上呈現(xiàn)執(zhí)行Chromium 。

  方法page.cookies返回一個對象數(shù)組,每個對象定義一個 cookie 并包含兩個屬性:名稱和值 。使用一系列 Lodash 函數(shù),循環(huán)提取每個 cookie 的鍵值對,并生成類似于下面的字符串:

文件 cookie-storage.js:

// cookie-storage.js

// cookie storage variable
let localProcessedCookie = null;

// getter
const getLocalCookie = () => localProcessedCookie;

// setter
const setLocalCookie = (cookie) => {
localProcessedCookie = cookie;

// lock the getLocalCookie function;
// its scope with the localProcessedCookie value will be saved
// after the setLocalCookie function completes
return getLocalCookie;
};

module.exports = {
setLocalCookie,
getLocalCookie,
};

  對于閉包的定義,明確的思路是:在該變量作用域內(nèi)的函數(shù)結(jié)束后,保持對某個變量值的訪問。通常,當函數(shù)完成執(zhí)行返回操作時,它會離開調(diào)用堆棧,垃圾回收機制會從作用域內(nèi)刪除內(nèi)存中的所有變量。

  上面的示例中,本地cookie設(shè)置器完成設(shè)置后,應(yīng)該回收的本地已處理cookie變量的值將保留在計算機的內(nèi)存中。這就意味著只要應(yīng)用程序在運行,它就可以在代碼中的任何地方獲取這個值。

  這樣,當調(diào)用setLocalCookie時,將從中返回getLocalCookie函數(shù)。一旦這個LocalCookie函數(shù)作用域面臨回收時,NodeJS能夠看到它具有g(shù)etLocalCookie閉包函數(shù)。此時,垃圾回收機制將返回的獲取器作用域內(nèi)的所有變量都保留在內(nèi)存中。由于可變的本地處理Cookie在getLocalCookie的作用域內(nèi),因此它將繼續(xù)存在,保持與Cookie的綁定。

URL生成器

  應(yīng)用程序需要一個url的主列表才能開始爬取。在生產(chǎn)過程中,爬取通常從Web資源的主頁開始,經(jīng)過一定數(shù)量次數(shù)的迭代,最終建立一個指向登錄頁面的鏈接集合。通常,一個Web資源有成千上萬個這樣的鏈接。

  在此示例中,爬取程序只會傳輸8個爬取鏈接作為輸入,鏈接指向包含著主要產(chǎn)品分類目錄的頁面,它們分別是:

??  https://outlet.scotch-soda.com/women/clothing??

??  https://outlet.scotch-soda.com/women/footwear??

??  https://outlet.scotch-soda.com/women/accessories/all-womens-accessories??

??  https://outlet.scotch-soda.com/men/clothing??

??  https://outlet.scotch-soda.com/men/footwear??

??  https://outlet.scotch-soda.com/men/accessories/all-mens-accessories??

??  https://outlet.scotch-soda.com/kids/girls/clothing/all-girls-clothing??

??  https://outlet.scotch-soda.com/kids/boys/clothing/all-boys-clothing??

  使用這么長的鏈接字符,會影響代碼美觀性,為了避免這種情形,讓我們用下列文件創(chuàng)建一個短小精悍的URL構(gòu)建器:

  categories.js: 包含路由參數(shù)的文件;

  target-builder.js: 構(gòu)建url集合的文件.

  /project_root

  |__ /src

  |   |__ /constants

  | |  |__ **categories.js**

  |   |__ /helpers

  |      |__ cookie-manager.js

  |      |__ cookie-storage.js

  |      |__ **target-builder.js**

  |**__ .env**

  |__ index.js

  添加以下代碼:

  // .env

  MAIN_PAGE=https://outlet.scotch-soda.com

// index.js

// import builder function
const getTargetUrls = require('./src/helpers/target-builder');

(async () => {
// here the proccess of getting cookie

// gets an array of url links and determines it's length L
const targetUrls = getTargetUrls();
const { length: L } = targetUrls;

})();
// categories.js

module.exports = [
'women/clothing',
'women/footwear',
'women/accessories/all-womens-accessories',
'men/clothing',
'men/footwear',
'men/accessories/all-mens-accessories',
'kids/girls/clothing/all-girls-clothing',
'kids/boys/clothing/all-boys-clothing',
];
// target-builder.js

const path = require('path');
const categories = require('../constants/categories');

// static fragment of route parameters
const staticPath = 'global/en';

// create URL object from main page address
const url = new URL(process.env.MAIN_PAGE);

// add the full string of route parameters to the URL object
// and return full url string
const addPath = (dynamicPath) => {
url.pathname = path.join(staticPath, dynamicPath);

return url.href;
};

// collect URL link from each element of the array with categories
module.exports = () => categories.map((category) => addPath(category));

  這三個代碼片段構(gòu)建了本段開頭給出的8個鏈接,演示了內(nèi)置的URL以及路徑庫的使用。可能有人會覺得,這不是大炮打蚊子嘛!使用插值明明更簡單啊!

  有明確規(guī)范的NodeJS方法用于處理路由以及URL請求參數(shù),主要是基于以下兩個原因:

  1、插值在輕量級應(yīng)用下還好;

  2、為了養(yǎng)成良好的習(xí)慣,應(yīng)當每天使用。

爬網(wǎng)和抓取

  向服務(wù)器應(yīng)用程序的邏輯中心添加兩個文件:

  ·crawler.js:包含用于向 Web 服務(wù)器發(fā)送請求和接收網(wǎng)頁標記的爬網(wǎng)程序類;

  ·parser.js:包含解析器類,其中包含用于抓取標記和獲取目標數(shù)據(jù)的方法。

  /project_root

  |__ /src

  |   |__ /constants

  | |  |__ categories.js

  |   |__ /helpers

  |   |  |__ cookie-manager.js

  |   |  |__ cookie-storage.js

  |   |  |__ target-builder.js

  ****|   |__ **crawler.js**

  |   |__ **parser.js**

  |**__** .env

  |__ **index.js**

  首先,添加一個循環(huán)index.js,它將依次傳遞URL鏈接到爬取程序并接收解析后的數(shù)據(jù):

// index.js

const crawler = new Crawler();

(async () => {
// getting Cookie proccess
// and url-links array...
const { length: L } = targetUrls;

// run a loop through the length of the array of url links
for (let i = 0; i < L; i += 1) {
// call the run method of the crawler for each link
// and return parsed data
const result = await crawler.run(targetUrls[i]);

// do smth with parsed data...
}
})();

  爬取代碼:

// crawler.js

require('dotenv').config();
const cheerio = require('cheerio');
const axios = require('axios').default;
const UserAgent = require('user-agents');

const Parser = require('./parser');
// getLocalCookie - closure function, returns localProcessedCookie
const { getLocalCookie } = require('./helpers/cookie-storage');

module.exports = class Crawler {
constructor() {
// create a class variable and bind it to the newly created Axios object
// with the necessary headers
this.axios = axios.create({
headers: {
cookie: getLocalCookie(),
'user-agent': (new UserAgent()).toString(),
},
});
}

async run(url) {
console.log('IScraper: working on %s', url);

try {
// do HTTP request to the web server
const { data } = await this.axios.get(url);
// create a cheerio object with nodes from html markup
const $ = cheerio.load(data);

// if the cheerio object contains nodes, run Parser
// and return to index.js the result of parsing
if ($.length) {
const p = new Parser($);

return p.parse();
}
console.log('IScraper: could not fetch or handle the page content from %s', url);
return null;
} catch (e) {
console.log('IScraper: could not fetch the page content from %s', url);

return null;
}
}
};

  解析器的任務(wù)是在接收到 cheerio 對象時選擇數(shù)據(jù),然后為每個 URL 鏈接構(gòu)建以下結(jié)構(gòu):

[
{
"Title":"Graphic relaxed-fit T-shirt | Women",
"CurrentPrice":25.96,
"Currency":"€",
"isNew":false
},
{
// at all 36 such elements for every url-link
}
]

  解析代碼:

// parser.js

require('dotenv').config();
const _ = require('lodash');

module.exports = class Parser {
constructor(content) {
// this.$ - this is a cheerio object parsed from the markup
this.$ = content;
this.$$ = null;
}

// The crawler calls the parse method
// extracts all 'li' elements from the content block
// and in the map loop the target data is selected
parse() {
return this.$('#js-search-result-items')
.children('li')
.map((i, el) => {
this.$$ = this.$(el);

const Title = this.getTitle();
const CurrentPrice = this.getCurrentPrice();

// if two key values are missing, such object is rejected
if (!Title || !CurrentPrice) return {};

return {
Title,
CurrentPrice,
Currency: this.getCurrency(),
isNew: this.isNew(),
};
})
.toArray();
}

// next - private methods, which are used at 'parse' method
getTitle() {
return _.replace(this.$$.find('.product__name').text().trim(), /\s{2,}/g, ' ');
}

getCurrentPrice() {
return _.toNumber(
_.replace(
_.last(_.split(this.$$.find('.product__price').text().trim(), ' ')),
',',
'.',
),
);
}

getCurrency() {
return _.head(_.split(this.$$.find('.product__price').text().trim(), ' '));
}

isNew() {
return /new/.test(_.toLower(this.$$.find('.content-asset p').text().trim()));
}
};

  爬取程序和解析器運行的結(jié)果將是8個內(nèi)部包含對象的數(shù)組,并傳遞回index.js文件的for循環(huán)。

  流寫入文件

  要寫入一個文件,須使用可寫流。流是一種JS對象,包含了許多用于處理按順序出現(xiàn)的數(shù)據(jù)塊的方法。所有的流都繼承自EventEmitter類(即事件觸發(fā)器),因此,它們能夠?qū)\行環(huán)境中的突發(fā)事件做出反應(yīng)。或許有人遇到過下面這種情形:

myServer.on('request', (request, response) => {
// something puts into response
});

// or

myObject.on('data', (chunk) => {
// do something with data
});

  這是NodeJS流的優(yōu)秀范例,盡管它們的名字不那么原始:我的服務(wù)器和我的對象。在此示例中,它們偵聽某些事件:HTTP請求(事件)的到達和一段數(shù)據(jù)(事件)的到達,然后安排它們各就各位去工作。“流式傳輸”的立足之本在于它們使用片狀數(shù)據(jù)片段,并且只需要極低的運行內(nèi)存。

  在此情形下,for循環(huán)按順序接收 8 個包含數(shù)據(jù)的數(shù)組,這些數(shù)組將按順序?qū)懭胛募鵁o需等待累積完整的集合,也無需使用任何累加器。執(zhí)行示例代碼時,由于能夠得知下一部分解析數(shù)據(jù)到達for循環(huán)的確切時刻,所以無需任何偵聽,就可以使用內(nèi)置于流中的方法立即寫入。

  寫入到何處

  /project_root

  |__ /data

  |   |__ **data.json**

  ...

// index.js

const fs = require('fs');
const path = require('path');
const { createWriteStream } = require('fs');

// use constants to simplify work with addresses
const resultDirPath = path.join('./', 'data');
const resultFilePath = path.join(resultDirPath, 'data.json');

// check if the data directory exists; create if it's necessary
// if the data.json file existed - delete all data
// ...if not existed - create empty
!fs.existsSync(resultDirPath) && fs.mkdirSync(resultDirPath);
fs.writeFileSync(resultFilePath, '');

(async () => {
// getting Cookie proccess
// and url-links array...

// create a stream object for writing
// and add square bracket to the first line with a line break
const writer = createWriteStream(resultFilePath);
writer.write('[\n');

// run a loop through the length of the url-links array
for (let i = 0; i < L; i += 1) {
const result = await crawler.run(targetUrls[i]);

// if an array with parsed data is received, determine its length l
if (!_.isEmpty(result)) {
const { length: l } = result;

// using the write method, add the next portion
//of the incoming data to data.json
for (let j = 0; j < l; j += 1) {
if (i + 1 === L && j + 1 === l) {
writer.write(` ${JSON.stringify(result[j])}\n`);
} else {
writer.write(` ${JSON.stringify(result[j])},\n`);
}
}
}
}
})();

  嵌套的for循環(huán)解決了一個問題:為在輸出中獲取有效的json文件,需要注意結(jié)果數(shù)組中的最后一個對象后面不要有逗號。嵌套for循環(huán)決定哪個對象是應(yīng)用程序中最后一個撤消插入逗號的。

  如果事先創(chuàng)建data/data.json并在代碼運行時打開,就可以實時看到可寫流是如何按順序添加新數(shù)據(jù)片段的。

  結(jié)論

  輸出結(jié)果是以下形式的JSON對象:

[
{"Title":"Graphic relaxed-fit T-shirt | Women","CurrentPrice":25.96,"Currency":"€","isNew":false},
{"Title":"Printed mercerised T-shirt | Women","CurrentPrice":29.97,"Currency":"€","isNew":true},
{"Title":"Slim-fit camisole | Women","CurrentPrice":32.46,"Currency":"€","isNew":false},
{"Title":"Graphic relaxed-fit T-shirt | Women","CurrentPrice":25.96,"Currency":"€","isNew":true},
...
{"Title":"Piped-collar polo | Boys","CurrentPrice":23.36,"Currency":"€","isNew":false},
{"Title":"Denim chino shorts | Boys","CurrentPrice":45.46,"Currency":"€","isNew":false}
]

  應(yīng)用程序授權(quán)處理時間約為20秒。

  完整的開源項目代碼存在GitHub上。并附有依賴關(guān)系程序包package.json。

譯者介紹

  張哲剛,51CTO社區(qū)編輯,系統(tǒng)運維工程師,國內(nèi)較早一批硬件評測及互聯(lián)網(wǎng)從業(yè)者,曾入職阿里巴巴。十余年IT項目管理經(jīng)驗,具備復(fù)合知識技能,曾參與多個網(wǎng)站架構(gòu)設(shè)計、電子政務(wù)系統(tǒng)開發(fā),主導(dǎo)過某地市級招生考試管理平臺運維工作。

  原文標題:Web Scraping Sites With Session Cookie Authentication Using NodeJS Request

  鏈接:

??  https://hackernoon.com/web-scraping-sites-with-session-cookie-authentication-using-nodejs-request??

責任編輯:張潔
相關(guān)推薦

2013-08-21 10:08:16

2015-09-24 09:22:16

nodejs頁面始末

2021-06-29 15:52:03

PythonPOST

2012-03-02 10:18:31

2021-01-18 05:11:14

通信Nodejs進程

2012-02-24 15:25:45

ibmdw

2020-11-04 07:17:42

Nodejs通信進程

2023-01-03 09:01:21

2011-09-02 11:06:28

Oracle服務(wù)器進程為事務(wù)建立回滾段放入dirty lis

2021-07-28 09:00:00

編程語言Kotlin開發(fā)

2020-02-07 10:46:31

Python數(shù)據(jù)庫MySQL

2020-03-04 14:48:13

Python 開發(fā)編程語言

2014-09-03 10:09:23

LinuxOpenswan

2009-09-25 11:14:16

Hibernate批量

2013-07-22 13:48:55

iOS開發(fā)ASIHTTPRequ使用Cookie

2011-02-18 11:02:28

2013-08-21 09:21:01

2012-12-10 10:32:22

2023-03-09 15:55:17

JavaScriptURLCSS

2017-01-20 08:44:53

Apache Flum抓取數(shù)據(jù)
點贊
收藏

51CTO技術(shù)棧公眾號

久久亚洲精精品中文字幕早川悠里 | 国产又粗又猛又爽又| 国产99久久精品一区二区300| 91搞黄在线观看| 99精品视频网站| 五十路在线观看| 老鸭窝一区二区久久精品| 亚洲福利免费| 91免费国产视频网站| 国产精品免费视频xxxx| 青青草手机在线观看| 亚洲激情播播| 日韩欧美的一区二区| 成年人在线看片| 在线观看av免费| 国产亚洲欧美激情| 国产欧美日韩亚洲| 91亚洲国产成人精品一区| 一区二区三区高清视频在线观看| 中文字幕久久精品| 好吊色视频一区二区三区| 不卡亚洲精品| 欧美色视频日本高清在线观看| 中文字幕日韩精品一区二区| 欧美成人综合在线| 成人综合在线视频| 91在线高清免费观看| 免费观看日批视频| 亚洲精品美女| 九九九久久久久久| 国产亚洲精品久久久久久豆腐| 欧美电影在线观看完整版| 91精品麻豆日日躁夜夜躁| 国产男女激情视频| 天堂在线中文网官网| 亚洲超丰满肉感bbw| 国产日韩视频在线播放| 337p日本欧洲亚洲大胆鲁鲁| 久久午夜色播影院免费高清| 国产女主播一区二区三区| 精品人妻一区二区三区换脸明星 | 亚洲卡通欧美制服中文| 视频一区在线免费观看| 俄罗斯精品一区二区| 亚洲成人第一网站| 9久re热视频在线精品| 欧美激情亚洲另类| 久久艹精品视频| 亚洲国产一成人久久精品| 中文字幕在线日韩 | 亚洲精品高清无码视频| 忘忧草在线影院两性视频| 亚洲电影中文字幕在线观看| 成人国产在线看| 污污的网站在线看| 亚洲综合视频在线观看| 天堂8在线天堂资源bt| 9lporm自拍视频区在线| 亚洲国产综合色| 久久久久久久久久网| av免费不卡国产观看| 亚洲福利视频导航| 又粗又黑又大的吊av| 在线看片福利| 色播五月激情综合网| 蜜臀视频一区二区三区| 免费av中文字幕| 免费大片在线观看www| 国产女人18水真多18精品一级做| 奇米888一区二区三区| 激情综合闲人网| 国产精品丝袜黑色高跟| 天堂v在线视频| 在线h片观看| 精品国产乱码久久久久久虫虫漫画| 无码播放一区二区三区| 亚洲综合在线电影| 欧美精品在线视频| 高清中文字幕mv的电影| 在线视频亚洲专区| 精品国模在线视频| 国产乡下妇女做爰| 日本视频中文字幕一区二区三区| 91精品久久久久久久| 精品国自产在线观看| 99re热这里只有精品视频| 茄子视频成人在线观看 | 俄罗斯嫩小性bbwbbw| 97久久超碰国产精品电影| 日本一区二区在线视频| av在线下载| 一本色道久久综合亚洲91 | 精品人妻人人做人人爽夜夜爽| 在线观看中文字幕的网站| 婷婷激情综合网| 国产一二三区av| 超碰精品在线观看| 在线播放日韩欧美| 久久久久99精品| 蜜臀av性久久久久av蜜臀妖精| 91天堂在线观看| 三级在线观看| 亚洲精品国产视频| 看欧美ab黄色大片视频免费| 日韩高清一区| 中文字幕av一区中文字幕天堂 | 国产日韩欧美精品| 麻豆视频网站在线观看| 日韩欧美999| 国产人妖在线观看| 日韩理论片av| 青青在线视频一区二区三区| www黄色网址| 国产精品毛片无遮挡高清| 高清在线观看免费| 亚洲精品一区国产| 日韩亚洲一区二区| 免费黄色小视频在线观看| 成人午夜在线视频| 国产欧美123| 在线欧美激情| 亚洲人午夜精品天堂一二香蕉| 亚洲精品98久久久久久中文字幕| 自拍视频一区二区| 欧美精品自拍| 成人免费午夜电影| 91亚洲精选| 色婷婷av一区| 极品粉嫩小仙女高潮喷水久久| 午夜精品久久久久99热蜜桃导演 | 欧美国产成人在线| 国产免费黄色av| 成人av动漫| 两个人的视频www国产精品| 一级黄色大片免费观看| 久久久精品欧美丰满| 3d动漫一区二区三区| 亚洲精品在线播放| 欧美超级免费视 在线| 在线免费观看一区二区| 国产欧美一区二区精品婷婷| 国产精品欧美激情在线观看| 久久狠狠久久| 97精品一区二区三区| 老牛影视av牛牛影视av| 亚洲午夜电影网| 国产精品成久久久久三级| 国产精品伦子伦| 日韩亚洲国产精品| 精品一区二区三区国产| 操人在线观看| 亚洲美女动态图120秒| 久久夜色精品国产噜噜亚洲av| 91免费视频大全| 欧美成人xxxxx| 久操精品在线| 国产精品成人久久久久| 国产成人天天5g影院在线观看| 色婷婷久久综合| 韩国三级hd中文字幕| 奇米色777欧美一区二区| 亚洲精品中文字幕在线| 麻豆久久久久| 欧美精品在线免费播放| 成人午夜免费在线观看| 调教+趴+乳夹+国产+精品| 日本黄色片在线播放| 久久不射2019中文字幕| 性高潮久久久久久久久| 99国内精品久久久久| 欧美猛男性生活免费| 日韩一区二区三区不卡| 欧美性猛交xxxx偷拍洗澡| 欧美色图17p| 丁香桃色午夜亚洲一区二区三区| 很污的网站在线观看| 香蕉精品久久| 国产精品视频一区国模私拍| 黄色片免费在线观看| 精品动漫一区二区三区在线观看| 亚洲日本视频在线观看| 国产精品美女一区二区三区| 国产探花一区二区三区| 亚洲一区二区毛片| 亚洲国产一区二区精品视频| 日韩视频1区| 国产成人精品久久久| 免费大片黄在线观看视频网站| 精品国产伦理网| 日本成人一级片| 一区二区三区四区视频精品免费 | 高清乱码毛片入口| 色先锋aa成人| 久久福利免费视频| 99久久精品国产一区| 欧美三级午夜理伦三级富婆| 黄色日韩精品| 亚洲精品欧洲精品| 久久激情av| 5g国产欧美日韩视频| 欧美aaa视频| 亚洲91中文字幕无线码三区| 日韩男女性生活视频| 中文字幕免费高清电视剧网站在线观看| 日韩精品免费在线| 99久久久久成人国产免费| 欧美日韩综合视频网址| 劲爆欧美第一页| 国产精品毛片久久久久久久| 亚洲av无码一区二区二三区| 国产精品一区二区在线观看不卡| 国产美女三级视频| 亚洲午夜一区| 99精品一区二区三区的区别| 欧美日韩xxxx| 精品欧美国产| 亚洲一区二区免费在线观看| 国产精品一区二区电影| 成人免费影院| 97精品国产97久久久久久免费| av网站大全在线| 色妞久久福利网| 精品av中文字幕在线毛片| 精品国产一区久久| 国产三级小视频| 欧美高清激情brazzers| 免费观看日批视频| 色综合天天综合网天天狠天天| 久久久一二三区| 亚洲欧洲综合另类在线| 日韩一区二区三区四区视频| 国产丝袜欧美中文另类| 在线免费观看成年人视频| 国产精品538一区二区在线| 日本特黄a级片| 免费在线观看视频一区| 午夜免费一区二区| 日欧美一区二区| 国产真实乱子伦| 西西人体一区二区| 免费观看日韩毛片| 国产亚洲在线| 国产日产欧美视频| 香蕉久久夜色精品| 亚洲中文字幕无码不卡电影| 国产精品亚洲欧美| 欧美 国产 日本| 老司机久久99久久精品播放免费| 狠狠97人人婷婷五月| 国产精品美女| 麻豆av免费在线| 天堂成人国产精品一区| 男女爽爽爽视频| 秋霞影院一区二区| 在线看的黄色网址| 国产在线日韩欧美| 精产国品一区二区三区| 夫妻av一区二区| 好男人香蕉影院| 99精品国产视频| 无码 人妻 在线 视频| 国产精品视频麻豆| 亚洲区一区二区三| 亚洲美女偷拍久久| 国产一级视频在线| 欧美日韩国产精品一区二区三区四区| 毛片毛片女人毛片毛片| 在线观看91视频| 国产精品无码白浆高潮| 欧美xxxx在线观看| 亚洲欧美日韩精品永久在线| 亚洲天堂一区二区三区| 麻豆影院在线| 97国产suv精品一区二区62| 原纱央莉成人av片| 国产在线拍偷自揄拍精品| 中文在线综合| 青青草原成人| 欧美日韩精品| 久久久999视频| 麻豆成人综合网| www.啪啪.com| 欧美极品少妇xxxxⅹ高跟鞋 | 婷婷精品进入| 日本欧美视频在线观看| 日本午夜一本久久久综合| 妖精视频在线观看| 久久精品夜色噜噜亚洲aⅴ| 久久高清内射无套| 色综合久久中文字幕| 国产美女明星三级做爰| 国产婷婷97碰碰久久人人蜜臀| 日本视频在线播放| 5252色成人免费视频| 伊人久久大香| 欧美日韩在线精品| 综合一区二区三区| 不要播放器的av网站| 国产mv日韩mv欧美| 337人体粉嫩噜噜噜| 亚洲成av人片在www色猫咪| 一级特黄录像免费看| 日韩精品极品在线观看播放免费视频| 色影院视频在线| 日本久久久久久久| 成人偷拍自拍| 在线视频精品一区| 可以看av的网站久久看| 2一3sex性hd| 亚洲日本丝袜连裤袜办公室| 亚洲第一网站在线观看| 日韩欧美国产wwwww| 调教视频免费在线观看| 欧美一级高清免费| 老司机aⅴ在线精品导航| 91成人在线视频观看| 琪琪一区二区三区| 中文字幕国产综合| 激情久久av一区av二区av三区| av天堂一区二区三区| 这里只有精品丝袜| 色老太综合网| 久久精彩视频| 日韩午夜黄色| 欧美久久久久久久久久久| 日韩理论片网站| 在线观看毛片视频| 伊人精品在线观看| 天天综合网天天| 免费观看成人高| 国产精品久久久免费| 日本护士做爰视频| 亚洲成av人片观看| 秋霞网一区二区| 欧美国产一区二区三区| 日本在线成人| 成人高清dvd| 国产成人av在线影院| 亚洲欧美一区二区三区四区五区| 欧美精品乱码久久久久久| 天天综合视频在线观看| 国产在线观看91精品一区| 97精品中文字幕| 国产一区二区在线观看免费视频| 中文字幕乱码日本亚洲一区二区 | 亚洲国产精品va在线| 爱看av在线入口| 国产视频在线观看一区| 亚洲片区在线| 国产一级二级在线观看| 日韩欧美aaa| 国产免费a∨片在线观看不卡| 国产成人亚洲精品| 成人在线国产| 午夜av中文字幕| 一区二区在线观看视频| 亚洲国产精品久久久久久6q| 国内精品一区二区三区| 视频小说一区二区| 污污视频网站免费观看| 国产精品久久毛片a| 国产99999| 国色天香2019中文字幕在线观看| 欧美日韩直播| 手机看片福利日韩| 亚洲丝袜制服诱惑| 成人乱码一区二区三区| 午夜欧美大片免费观看| 国产精品久久久久久久成人午夜| 国产欧美日韩精品在线| 最近中文字幕在线视频| 久久人人爽人人爽人人片亚洲 | 欧美一区二区三区四区久久| 亚洲综合图区| 免费看污久久久| 麻豆精品一区二区综合av| 欧美成人aaa片一区国产精品| 亚洲成人黄色网| 日韩经典一区| 国产午夜精品视频一区二区三区| 99久久精品免费| 一级特黄aaa大片| 97精品国产97久久久久久春色| 欧洲激情视频| 91精品国产高清91久久久久久| 黄色精品一区二区| 久操视频在线| 久久亚洲午夜电影| 精品一区二区三区在线播放| 日韩精品乱码久久久久久| 色哟哟入口国产精品| 福利在线一区| 一区二区三区入口| 亚洲大片一区二区三区| 永久免费在线观看视频| 久久精品magnetxturnbtih| 久久国产麻豆精品| 久久草视频在线| 久久精品91久久久久久再现| 欧美挤奶吃奶水xxxxx|