最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node.js爬蟲(chóng)實(shí)戰(zhàn):反爬策略和應(yīng)對(duì)方案(繞過(guò)限制)

 更新時(shí)間:2026年01月17日 16:06:15   作者:程序員agions  
文章介紹了Node.js常見(jiàn)的反爬措施,如User-Agent檢測(cè)、IP頻率限制、Cookie/Session檢測(cè)、瀏覽器指紋檢測(cè)、驗(yàn)證碼、JavaScript混淆與加密等,并提供了應(yīng)對(duì)策略,在爬取數(shù)據(jù)時(shí)要遵守法律和道德規(guī)范

道高一尺,魔高一丈。爬蟲(chóng)與反爬的戰(zhàn)爭(zhēng),永無(wú)止境。

?? 開(kāi)場(chǎng):一場(chǎng)貓鼠游戲

我曾經(jīng)爬過(guò)一個(gè)電商網(wǎng)站。

第一天,一切順利,數(shù)據(jù)嘩嘩地進(jìn)來(lái)。

第二天,開(kāi)始出現(xiàn) 403 錯(cuò)誤,大概 10% 的請(qǐng)求被攔截。

第三天,50% 的請(qǐng)求返回驗(yàn)證碼頁(yè)面。

第四天,我的 IP 被永久封禁了。

這就是爬蟲(chóng)工程師的日常:和網(wǎng)站的反爬系統(tǒng)斗智斗勇。

今天,我們來(lái)聊聊常見(jiàn)的反爬措施,以及如何(合法地)應(yīng)對(duì)它們。

??? 常見(jiàn)反爬措施

1. User-Agent 檢測(cè)

最基礎(chǔ)的反爬措施,檢查請(qǐng)求頭中的 User-Agent。

// ? 默認(rèn)的 axios User-Agent(會(huì)暴露你在用爬蟲(chóng))
// axios/1.7.9

// ? 默認(rèn)的 Puppeteer User-Agent(包含 HeadlessChrome 字樣)
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/131.0.0.0 Safari/537.36

// ? 正常瀏覽器的 User-Agent
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36

應(yīng)對(duì)方案:

// 隨機(jī) User-Agent
const userAgents = [
  // Chrome on Windows
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  // Chrome on Mac
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
  // Firefox on Windows
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
  // Safari on Mac
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
  // Edge on Windows
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
]

function getRandomUserAgent() {
  return userAgents[Math.floor(Math.random() * userAgents.length)]
}

// 使用
await page.setUserAgent(getRandomUserAgent())

2. IP 頻率限制

同一 IP 請(qǐng)求過(guò)于頻繁會(huì)被封禁。

應(yīng)對(duì)方案:代理 IP 池

// src/utils/proxyPool.js
const axios = require("axios")

class ProxyPool {
  constructor() {
    this.proxies = []
    this.currentIndex = 0
    this.failedProxies = new Set()
  }

  /**
   * 從代理服務(wù)商獲取代理列表
   */
  async fetchProxies() {
    // 示例:從免費(fèi)代理 API 獲取
    // 生產(chǎn)環(huán)境建議使用付費(fèi)代理服務(wù)
    const response = await axios.get("https://api.proxy-provider.com/list", {
      params: {
        apiKey: process.env.PROXY_API_KEY,
        count: 100,
        country: "CN",
      },
    })

    this.proxies = response.data.proxies.map((p) => ({
      host: p.ip,
      port: p.port,
      protocol: p.protocol || "http",
      username: p.username,
      password: p.password,
    }))

    console.log(`? 獲取到 ${this.proxies.length} 個(gè)代理`)
  }

  /**
   * 獲取下一個(gè)可用代理
   */
  getNext() {
    // 過(guò)濾掉失敗的代理
    const availableProxies = this.proxies.filter(
      (p) => !this.failedProxies.has(`${p.host}:${p.port}`)
    )

    if (availableProxies.length === 0) {
      throw new Error("沒(méi)有可用的代理")
    }

    // 輪詢(xún)
    this.currentIndex = (this.currentIndex + 1) % availableProxies.length
    return availableProxies[this.currentIndex]
  }

  /**
   * 標(biāo)記代理為失敗
   */
  markFailed(proxy) {
    this.failedProxies.add(`${proxy.host}:${proxy.port}`)
  }

  /**
   * 獲取代理 URL
   */
  getProxyUrl(proxy) {
    const { protocol, username, password, host, port } = proxy
    if (username && password) {
      return `${protocol}://${username}:${password}@${host}:${port}`
    }
    return `${protocol}://${host}:${port}`
  }
}

module.exports = { ProxyPool }

在 Puppeteer 中使用代理:

const { ProxyPool } = require("./utils/proxyPool")

const proxyPool = new ProxyPool()
await proxyPool.fetchProxies()

async function crawlWithProxy(url) {
  const proxy = proxyPool.getNext()

  const browser = await puppeteer.launch({
    headless: "new",
    args: [`--proxy-server=${proxy.host}:${proxy.port}`],
  })

  const page = await browser.newPage()

  // 如果代理需要認(rèn)證
  if (proxy.username && proxy.password) {
    await page.authenticate({
      username: proxy.username,
      password: proxy.password,
    })
  }

  try {
    await page.goto(url, { timeout: 30000 })
    return await page.content()
  } catch (error) {
    // 代理失敗,標(biāo)記并重試
    proxyPool.markFailed(proxy)
    throw error
  } finally {
    await browser.close()
  }
}

3. Cookie/Session 檢測(cè)

網(wǎng)站通過(guò) Cookie 追蹤用戶(hù)行為,異常行為會(huì)被標(biāo)記。

應(yīng)對(duì)方案:Cookie 管理

// src/utils/cookieManager.js
const fs = require("fs-extra")
const path = require("path")

class CookieManager {
  constructor(cookieDir = "./data/cookies") {
    this.cookieDir = cookieDir
  }

  /**
   * 保存 Cookie
   */
  async save(domain, cookies) {
    const filepath = path.join(this.cookieDir, `${domain}.json`)
    await fs.ensureDir(this.cookieDir)
    await fs.writeJson(filepath, cookies)
  }

  /**
   * 加載 Cookie
   */
  async load(domain) {
    const filepath = path.join(this.cookieDir, `${domain}.json`)
    if (await fs.pathExists(filepath)) {
      return fs.readJson(filepath)
    }
    return null
  }

  /**
   * 應(yīng)用 Cookie 到頁(yè)面
   */
  async applyToPage(page, domain) {
    const cookies = await this.load(domain)
    if (cookies) {
      await page.setCookie(...cookies)
      return true
    }
    return false
  }

  /**
   * 從頁(yè)面保存 Cookie
   */
  async saveFromPage(page, domain) {
    const cookies = await page.cookies()
    await this.save(domain, cookies)
  }
}

module.exports = { CookieManager }

4. 瀏覽器指紋檢測(cè)

網(wǎng)站通過(guò) JavaScript 收集瀏覽器特征,識(shí)別爬蟲(chóng)。

常見(jiàn)的指紋特征:

  • Canvas 指紋
  • WebGL 指紋
  • 字體列表
  • 屏幕分辨率
  • 時(shí)區(qū)
  • 語(yǔ)言
  • 插件列表

應(yīng)對(duì)方案:使用 Stealth 插件

const puppeteer = require("puppeteer-extra")
const StealthPlugin = require("puppeteer-extra-plugin-stealth")

// 使用 Stealth 插件
puppeteer.use(StealthPlugin())

// Stealth 插件會(huì)自動(dòng)處理:
// - navigator.webdriver 屬性
// - Chrome 運(yùn)行時(shí)特征
// - 語(yǔ)言和插件
// - WebGL 渲染器
// - 等等...

const browser = await puppeteer.launch({ headless: "new" })

手動(dòng)偽裝指紋:

async function setupFingerprint(page) {
  // 覆蓋 navigator.webdriver
  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(navigator, "webdriver", {
      get: () => undefined,
    })
  })

  // 覆蓋 navigator.plugins
  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(navigator, "plugins", {
      get: () => [
        { name: "Chrome PDF Plugin" },
        { name: "Chrome PDF Viewer" },
        { name: "Native Client" },
      ],
    })
  })

  // 覆蓋 navigator.languages
  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(navigator, "languages", {
      get: () => ["zh-CN", "zh", "en"],
    })
  })

  // 覆蓋 WebGL 渲染器
  await page.evaluateOnNewDocument(() => {
    const getParameter = WebGLRenderingContext.prototype.getParameter
    WebGLRenderingContext.prototype.getParameter = function (parameter) {
      if (parameter === 37445) {
        return "Intel Inc."
      }
      if (parameter === 37446) {
        return "Intel Iris OpenGL Engine"
      }
      return getParameter.call(this, parameter)
    }
  })
}

5. 驗(yàn)證碼

最常見(jiàn)的反爬措施之一。

應(yīng)對(duì)方案:

方案 1:使用打碼平臺(tái)

const axios = require("axios")

/**
 * 使用打碼平臺(tái)識(shí)別驗(yàn)證碼
 */
async function solveCaptcha(imageBase64, type = "common") {
  // 示例:使用某打碼平臺(tái) API
  const response = await axios.post("https://api.captcha-solver.com/solve", {
    apiKey: process.env.CAPTCHA_API_KEY,
    image: imageBase64,
    type: type, // common, slide, click, etc.
  })

  return response.data.result
}

// 在爬蟲(chóng)中使用
async function handleCaptcha(page) {
  // 檢測(cè)是否有驗(yàn)證碼
  const captchaElement = await page.$(".captcha-image")
  if (!captchaElement) return true

  // 截圖驗(yàn)證碼
  const imageBuffer = await captchaElement.screenshot()
  const imageBase64 = imageBuffer.toString("base64")

  // 調(diào)用打碼平臺(tái)
  const captchaCode = await solveCaptcha(imageBase64)

  // 輸入驗(yàn)證碼
  await page.type("#captcha-input", captchaCode)
  await page.click("#submit-captcha")

  // 等待驗(yàn)證結(jié)果
  await page.waitForNavigation({ timeout: 5000 })

  return true
}

方案 2:滑塊驗(yàn)證碼

/**
 * 處理滑塊驗(yàn)證碼
 */
async function handleSliderCaptcha(page) {
  // 獲取滑塊和背景圖
  const slider = await page.$(".slider-button")
  const background = await page.$(".slider-background")

  if (!slider || !background) return

  // 獲取滑塊位置
  const sliderBox = await slider.boundingBox()
  const bgBox = await background.boundingBox()

  // 計(jì)算需要滑動(dòng)的距離(實(shí)際項(xiàng)目中需要圖像識(shí)別)
  // 這里簡(jiǎn)化處理,假設(shè)已知距離
  const distance = 200

  // 模擬人類(lèi)滑動(dòng)軌跡
  const startX = sliderBox.x + sliderBox.width / 2
  const startY = sliderBox.y + sliderBox.height / 2

  await page.mouse.move(startX, startY)
  await page.mouse.down()

  // 生成人類(lèi)化的滑動(dòng)軌跡
  const tracks = generateHumanTrack(distance)

  for (const track of tracks) {
    await page.mouse.move(startX + track.x, startY + track.y)
    await page.waitForTimeout(track.delay)
  }

  await page.mouse.up()
}

/**
 * 生成人類(lèi)化的滑動(dòng)軌跡
 */
function generateHumanTrack(distance) {
  const tracks = []
  let current = 0

  // 先加速后減速
  const mid = distance * 0.7

  while (current < distance) {
    let step
    if (current < mid) {
      // 加速階段
      step = Math.random() * 10 + 5
    } else {
      // 減速階段
      step = Math.random() * 3 + 1
    }

    current = Math.min(current + step, distance)

    tracks.push({
      x: current,
      y: Math.random() * 2 - 1, // 輕微的 Y 軸抖動(dòng)
      delay: Math.random() * 20 + 10,
    })
  }

  return tracks
}

6. JavaScript 混淆與加密

網(wǎng)站使用混淆的 JS 代碼來(lái)隱藏?cái)?shù)據(jù)或生成簽名。

應(yīng)對(duì)方案:

/**
 * 攔截并分析網(wǎng)絡(luò)請(qǐng)求
 */
async function interceptRequests(page) {
  await page.setRequestInterception(true)

  const apiRequests = []

  page.on("request", (request) => {
    // 記錄 API 請(qǐng)求
    if (request.url().includes("/api/")) {
      apiRequests.push({
        url: request.url(),
        method: request.method(),
        headers: request.headers(),
        postData: request.postData(),
      })
    }
    request.continue()
  })

  page.on("response", async (response) => {
    if (response.url().includes("/api/")) {
      try {
        const data = await response.json()
        console.log("API 響應(yīng):", response.url(), data)
      } catch (e) {
        // 非 JSON 響應(yīng)
      }
    }
  })

  return apiRequests
}

/**
 * 在瀏覽器中執(zhí)行 JS 獲取加密參數(shù)
 */
async function getEncryptedParams(page, data) {
  // 假設(shè)網(wǎng)站有一個(gè)加密函數(shù) window.encrypt
  const encrypted = await page.evaluate((data) => {
    // 調(diào)用網(wǎng)站自己的加密函數(shù)
    if (typeof window.encrypt === "function") {
      return window.encrypt(data)
    }
    return null
  }, data)

  return encrypted
}

?? 高級(jí)偽裝技巧

1. 模擬真實(shí)用戶(hù)行為

/**
 * 模擬人類(lèi)瀏覽行為
 */
async function simulateHumanBehavior(page) {
  // 隨機(jī)滾動(dòng)
  await page.evaluate(() => {
    const scrollHeight = document.body.scrollHeight
    const randomScroll = Math.floor(Math.random() * scrollHeight * 0.5)
    window.scrollTo(0, randomScroll)
  })

  // 隨機(jī)停留
  await page.waitForTimeout(Math.random() * 2000 + 1000)

  // 隨機(jī)移動(dòng)鼠標(biāo)
  const viewport = page.viewport()
  const randomX = Math.floor(Math.random() * viewport.width)
  const randomY = Math.floor(Math.random() * viewport.height)
  await page.mouse.move(randomX, randomY)

  // 隨機(jī)點(diǎn)擊(非鏈接區(qū)域)
  // await page.click('body')
}

/**
 * 模擬打字
 */
async function humanType(page, selector, text) {
  await page.click(selector)

  for (const char of text) {
    await page.keyboard.type(char)
    // 隨機(jī)打字間隔
    await page.waitForTimeout(Math.random() * 150 + 50)
  }
}

2. 請(qǐng)求頭完整性

/**
 * 設(shè)置完整的請(qǐng)求頭
 */
async function setFullHeaders(page) {
  await page.setExtraHTTPHeaders({
    Accept:
      "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    "Cache-Control": "max-age=0",
    Connection: "keep-alive",
    "Sec-Ch-Ua":
      '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"macOS"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
  })
}

3. Referer 鏈偽造

/**
 * 模擬正常的訪(fǎng)問(wèn)路徑
 */
async function simulateNormalPath(page, targetUrl) {
  // 先訪(fǎng)問(wèn)首頁(yè)
  await page.goto("https://example.com/", {
    waitUntil: "networkidle2",
  })
  await page.waitForTimeout(2000)

  // 模擬搜索
  await page.type("#search-input", "關(guān)鍵詞")
  await page.click("#search-button")
  await page.waitForNavigation()
  await page.waitForTimeout(1500)

  // 點(diǎn)擊搜索結(jié)果進(jìn)入目標(biāo)頁(yè)面
  // 這樣 Referer 就是搜索結(jié)果頁(yè)
  await page.goto(targetUrl, {
    referer: page.url(),
  })
}

?? 反爬檢測(cè)自測(cè)

在開(kāi)始爬取之前,可以用這些網(wǎng)站測(cè)試你的爬蟲(chóng)是否會(huì)被檢測(cè):

async function testAntiDetection() {
  const browser = await puppeteer.launch({ headless: "new" })
  const page = await browser.newPage()

  // 測(cè)試 1: Bot 檢測(cè)
  await page.goto("https://bot.sannysoft.com/")
  await page.screenshot({ path: "test-bot.png" })

  // 測(cè)試 2: 瀏覽器指紋
  await page.goto("https://browserleaks.com/canvas")
  await page.screenshot({ path: "test-canvas.png" })

  // 測(cè)試 3: WebRTC 泄露
  await page.goto("https://browserleaks.com/webrtc")
  await page.screenshot({ path: "test-webrtc.png" })

  await browser.close()

  console.log("檢測(cè)結(jié)果已保存為截圖,請(qǐng)查看")
}

?? 法律與道德提醒

在使用這些技術(shù)之前,請(qǐng)務(wù)必注意:

  1. 遵守 robots.txt - 這是基本禮儀
  2. 控制請(qǐng)求頻率 - 不要給目標(biāo)網(wǎng)站造成壓力
  3. 不爬取敏感數(shù)據(jù) - 個(gè)人隱私、付費(fèi)內(nèi)容等
  4. 不用于非法目的 - 不倒賣(mài)、不詐騙
  5. 尊重網(wǎng)站的服務(wù)條款 - 有些網(wǎng)站明確禁止爬取

記?。杭夹g(shù)是中立的,但使用技術(shù)的人要有底線(xiàn)。

?? 系列總結(jié)

到這里,《Node.js 爬蟲(chóng)實(shí)戰(zhàn)指南》系列就完結(jié)了。

希望這個(gè)系列能幫你成為一個(gè)合格的爬蟲(chóng)工程師。

記?。号老x(chóng)是一門(mén)技術(shù),更是一門(mén)藝術(shù)。

到此這篇關(guān)于Node.js爬蟲(chóng)實(shí)戰(zhàn):反爬策略和應(yīng)對(duì)方案(繞過(guò)限制)的文章就介紹到這了,更多相關(guān)Node.js反爬蟲(chóng)和應(yīng)對(duì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • npm?install?404問(wèn)題解決方案

    npm?install?404問(wèn)題解決方案

    這篇文章主要給大家介紹了關(guān)于npm?install?404問(wèn)題解決的相關(guān)資料,npm install命令既可以下載服務(wù)器上的模塊,也可以在本地創(chuàng)建自己的模塊,需要的朋友可以參考下
    2023-08-08
  • NodeJs通過(guò)async/await處理異步的方法

    NodeJs通過(guò)async/await處理異步的方法

    本篇文章主要介紹了NodeJs通過(guò)async/await處理異步的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Node.js 數(shù)據(jù)庫(kù) CRUD 項(xiàng)目示例詳解(完美解決方案)

    Node.js 數(shù)據(jù)庫(kù) CRUD 項(xiàng)目示例詳解(完美解決方案)

    這篇文章主要介紹了Node.js 數(shù)據(jù)庫(kù) CRUD 項(xiàng)目示例詳解(完美解決方案),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-04-04
  • M2實(shí)現(xiàn)Nodejs項(xiàng)目自動(dòng)部署的方法步驟

    M2實(shí)現(xiàn)Nodejs項(xiàng)目自動(dòng)部署的方法步驟

    這篇文章主要介紹了M2實(shí)現(xiàn)Nodejs項(xiàng)目自動(dòng)部署的方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-05-05
  • 完美解決node.js中使用https請(qǐng)求報(bào)CERT_UNTRUSTED的問(wèn)題

    完美解決node.js中使用https請(qǐng)求報(bào)CERT_UNTRUSTED的問(wèn)題

    下面小編就為大家?guī)?lái)一篇完美解決node.js中使用https請(qǐng)求報(bào)CERT_UNTRUSTED的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • NodeJS制作爬蟲(chóng)全過(guò)程

    NodeJS制作爬蟲(chóng)全過(guò)程

    這篇文章主要介紹了NodeJS制作爬蟲(chóng)的全過(guò)程,包括項(xiàng)目建立,目標(biāo)網(wǎng)站分析、使用superagent獲取源數(shù)據(jù)、使用cheerio解析、使用eventproxy來(lái)并發(fā)抓取每個(gè)主題的內(nèi)容等方面,有需要的小伙伴參考下吧。
    2014-12-12
  • nodejs搭建本地http服務(wù)器教程

    nodejs搭建本地http服務(wù)器教程

    本篇文章主要介紹了nodejs搭建本地http服務(wù)器教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • node.js中的http.response.removeHeader方法使用說(shuō)明

    node.js中的http.response.removeHeader方法使用說(shuō)明

    這篇文章主要介紹了node.js中的http.response.removeHeader方法使用說(shuō)明,本文介紹了http.response.removeHeader的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node.js如何操作MySQL數(shù)據(jù)庫(kù)

    node.js如何操作MySQL數(shù)據(jù)庫(kù)

    這篇文章主要介紹了node.js如何操作MySQL數(shù)據(jù)庫(kù),幫助大家更好的進(jìn)行web開(kāi)發(fā),感興趣的朋友可以了解下
    2020-10-10
  • 使用nvm安裝node的詳細(xì)圖文教程

    使用nvm安裝node的詳細(xì)圖文教程

    nvm是nodejs的版本管理工具,可以在一個(gè)環(huán)境中同時(shí)安裝多個(gè)nodejs 版本(和配套的 npm 版本),并隨時(shí)切換,下面這篇文章主要給大家介紹了關(guān)于使用nvm安裝node的詳細(xì)圖文教程,需要的朋友可以參考下
    2023-02-02

最新評(píng)論

通许县| 东光县| 长寿区| 杭州市| 滦平县| 平度市| 焉耆| 普格县| 麦盖提县| 新密市| 彝良县| 泾源县| 修水县| 东山县| 枣庄市| 高青县| 长丰县| 句容市| 萍乡市| 滁州市| 舟山市| 普兰店市| 通江县| 盐源县| 上杭县| 四平市| 维西| 榆林市| 双牌县| 含山县| 竹北市| 府谷县| 崇仁县| 刚察县| 德庆县| 宜都市| 密云县| 高陵县| 常熟市| 绥江县| 潞城市|