fetch.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. const request = require('request-promise')
  2. const iconv = require('iconv-lite')
  3. const cheerio = require('cheerio')
  4. const md5 = require('md5')
  5. const path = require('path')
  6. const fs = require('fs')
  7. const retry = require('async-retry')
  8. const special = require('./special')
  9. function sleep(time) {
  10. return new Promise(resolve => {
  11. console.log(`sleep: ${time}`)
  12. setTimeout(() => {
  13. resolve()
  14. }, time)
  15. })
  16. }
  17. async function getPage(url, returnMeta = false) {
  18. let content = ''
  19. let isCache = false
  20. const id = md5(url)
  21. const file = `./temp/${id}.html`
  22. if (fs.existsSync(file)) {
  23. content = fs.readFileSync(file, 'utf-8')
  24. isCache = true
  25. } else {
  26. await retry(async bail => {
  27. try {
  28. const rs = await request(url, {
  29. resolveWithFullResponse: true,
  30. encoding: null,
  31. })
  32. content = iconv.decode(rs.body, 'gb2312')
  33. fs.writeFileSync(file, content)
  34. return true
  35. } catch (e) {
  36. // bail(new Error('FAIL'))
  37. }
  38. }, {
  39. retries: 50,
  40. minTimeout: 5000,
  41. onRetry: function () {
  42. console.log('retry')
  43. }
  44. })
  45. }
  46. if (returnMeta) {
  47. return {
  48. isCache,
  49. content
  50. }
  51. } else {
  52. return content
  53. }
  54. }
  55. ;
  56. (async() => {
  57. try {
  58. } catch (e) {
  59. console.log(e)
  60. }
  61. const cityIds = []
  62. const rs = {
  63. '86': {}
  64. }
  65. const level0 = await getPage(
  66. 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/index.html')
  67. const $ = cheerio.load(level0)
  68. const list = $('.provincetr td a')
  69. const provinces = []
  70. const urls = []
  71. list.each((index, el) => {
  72. const url =
  73. `http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/${$(el).attr('href')}`
  74. const data = {
  75. id: $(el).attr('href').split('.')[0] + '0000',
  76. name: $(el).text()
  77. }
  78. rs['86'][data.id] = data.name
  79. urls.push(url)
  80. })
  81. const specialProvinces = {
  82. "710000": "台湾省",
  83. "810000": "香港特别行政区",
  84. "820000": "澳门特别行政区"
  85. }
  86. Object.assign(rs['86'], specialProvinces)
  87. // 市
  88. for (const url of urls) {
  89. const level1 = await getPage(url)
  90. const $ = cheerio.load(level1)
  91. const list = $('.citytr td a')
  92. const countyUrls = []
  93. list.each(async(index, el) => {
  94. const url =
  95. `http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/${$(el).attr('href')}`
  96. // filter number
  97. const text = $(el).text()
  98. if (!/\d+/.test(text)) {
  99. const data = {
  100. id: $(el).attr('href').split('.')[0].slice(3) + '00',
  101. name: $(el).text()
  102. }
  103. const parentId = data.id.slice(0, 2) + '0000'
  104. if (!rs[parentId]) {
  105. rs[parentId] = {}
  106. }
  107. cityIds.push(data.id)
  108. rs[parentId][data.id] = data.name
  109. }
  110. countyUrls.push(url)
  111. })
  112. for (const url of countyUrls) {
  113. const level2 = await getPage(url)
  114. const $ = cheerio.load(level2)
  115. const list = $('.countytr td, .towntr td')
  116. let townUrls = []
  117. const currentUrl = url
  118. for (let index = 0; index < list.length; index++) {
  119. const { data, url } = processLinks($, list, index, currentUrl.split('/')[7] + '/')
  120. if (data.id) {
  121. console.log(data)
  122. if (data.isLink) {
  123. data.id = data.id.split('.')[0].split('/')[1]
  124. } else {
  125. data.id = data.id.replace(/0+$/g, '')
  126. }
  127. const parentId = data.id.slice(0, 4) + '00'
  128. if (!rs[parentId]) {
  129. rs[parentId] = {}
  130. }
  131. rs[parentId][data.id] = data.name
  132. }
  133. if (url) {
  134. townUrls.push(url)
  135. }
  136. }
  137. // console.log('街道数量', townUrls.length)
  138. // townUrls = Array.from(new Set(townUrls))
  139. // for (const town of townUrls) {
  140. // console.log('获取街道')
  141. // console.log('url', url, town)
  142. // console.log(url.split('/')[7])
  143. // const level3 = await getPage(town, true)
  144. // if (!level3.isCache) {
  145. // await sleep(2000)
  146. // }
  147. // const $ = cheerio.load(level3.content)
  148. // const list = $('.towntr td')
  149. //
  150. // for (let index = 0; index < list.length; index++) {
  151. // const { data, url } = processLinks($, list, index)
  152. // // data.id = data.id.split('/')[1].split('.')[0]
  153. // if (data.id) {
  154. // console.log(data)
  155. // }
  156. // }
  157. // }
  158. }
  159. }
  160. setInterval(() => {
  161. // return
  162. fs.writeFileSync('../data.json', JSON.stringify(Object.assign({}, rs,
  163. special), null, 2))
  164. fs.writeFileSync('./data.json', JSON.stringify(Object.assign({}, rs,
  165. special), null, 2))
  166. const _2levelCityIds = cityIds.filter(c => !Object.keys(rs[c] || {}).length)
  167. fs.writeFileSync('./only_2_level_city_id.json', JSON.stringify(
  168. _2levelCityIds, null, 2))
  169. console.log('done')
  170. // process.exit(0)
  171. }, 6000)
  172. })()
  173. function processLinks ($, list, index, linkPrefix = '') {
  174. const el = list[index]
  175. const link = $(el).find('a')
  176. let url
  177. if ($(link[0]).attr('href')) {
  178. url =
  179. `http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/${linkPrefix}${$(link[0]).attr('href')}`
  180. }
  181. let data = {}
  182. if (link.length) {
  183. if (!/\d+/.test($(el).text())) {
  184. data = {
  185. isLink: true,
  186. id: $(link[0]).attr('href'),
  187. name: $(el).text()
  188. }
  189. }
  190. } else {
  191. if (!/\d+/.test($(el).text())) {
  192. data = {
  193. isLink: false,
  194. id: $(list[index - 1]).text(),
  195. name: $(el).text()
  196. }
  197. }
  198. }
  199. // console.log(data, url)
  200. return {
  201. data,
  202. url,
  203. }
  204. }