pyspider框架之ajax資料爬取
阿新 • • 發佈:2019-01-28
pyspider框架之記錄1
- 由於公司業務需求,目前做的爬蟲就是爬取全國各個政府釋出的各種政策,平時寫的程式碼,沒有多少想寫成部落格的,後續可能都會寫出來,今天遇到了一個政府網站採用了ajax非同步更新技術,那就做個記錄吧。。
- 目標政府的url地址為http://www.hangzhou.gov.cn/col/col1255929/index.html。
- 首先網頁進行簡單分析,因為目標網站存在多頁的情況的,一般情況,進行翻頁,上邊位址列的url地址會跟著翻頁跳轉發生有規律的變化,但是此網站不是這樣,因為採用了ajax非同步更新技術。如下圖
- 對於ajax非同步請求的資料來說,首先考慮從右鍵->檢查->network裡抓包分析,如果不容易進行抓包分析,可以藉助抓包工具fiddler等,還可以可以藉助selenuim自動化網頁測試等工具。本次爬蟲比較簡單,通過簡單的抓包就可以獲取到ajax非同步請求的url地址。如下圖
由上圖可以,翻一次頁,會多一個左下角的請求檔案,從右下角即可看到傳送請求的url地址,並且採用的是post請求方式,爬蟲時需要有請求體data資料,data資料的內容如下圖
- 接下來,就可以用pyspider框架進行爬取資料了,pyspider是一個相對Scrapy簡單的框架,本文不對其使用進行詳細描述,後續會單獨寫pyspider的相關教程。分析完畢,將爬取的資料儲存至本地的mongodb資料庫。現將完整程式碼附上
- 首先網頁進行簡單分析,因為目標網站存在多頁的情況的,一般情況,進行翻頁,上邊位址列的url地址會跟著翻頁跳轉發生有規律的變化,但是此網站不是這樣,因為採用了ajax非同步更新技術。如下圖
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2018-06-01 14:20:47
# Project: guojiatongji
# 杭州市人民政府 -. 資訊公開 -> 市政府資訊公開目錄
from pyspider.libs.base_handler import *
from pymongo import MongoClient
import datetime
import re
DB_IP = '127.0.0.1'
DB_PORT = 27017
DB_NAME = 'research'
DB_COL = 'hangzhou'
client = MongoClient(host=DB_IP, port=DB_PORT)
db = client[DB_NAME]
col = db[DB_COL]
class Handler(BaseHandler):
url = 'http://www.hangzhou.gov.cn/col/col1255929/index.html'
crawl_config = {
"headers": {
"User-Agent": "Mozilla/5.0 (X11;Linux x86_64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/66.0.3359.181 Safari/537.36"
}
}
def format_date(self, date):
return datetime.datetime.strptime(date, '%Y-%m-%d')
@every(minutes=24 * 60)
def on_start(self):
self.crawl(self.url, fetch_type='js', callback=self.index_page)
@config(age=60)
def index_page(self, response):
page = response.etree
total_page_str = page.xpath("//table[@class='tb_title']/tbody/tr/td/text()")[0].encode('utf-8')
print
total_page_str
total_page = int(re.findall('共(\d+)頁', total_page_str)[0])
print
total_page
# 請求的url
base_url = 'http://www.hangzhou.gov.cn/module/xxgk/search.jsp?'
# 請求體
data = {"infotypeId": "",
"jdid": 149,
"area": "",
"divid": "div1269023",
"vc_title": "",
"vc_number": "",
"vc_filenumber": "",
"vc_all": "",
"texttype": 0,
"fbtime": -1,
"texttype": 0,
"fbtime": -1,
"vc_all": "",
"vc_filenumber": "",
"vc_title": "",
"vc_number": "",
"sortfield": ""
}
# 翻頁
for page_num in range(1, total_page + 1):
page_url = base_url + 'currpage={}&'.format(page_num)
print
page_url
self.crawl(page_url, callback=self.parse_page, method='POST', data=data)
def parse_page(self, response):
page = response.etree
categories = ["中國杭州"]
content_list = page.xpath("//div")[2].xpath(".//tr")
# 每頁內容
for each in content_list:
content_title = each.xpath("./td/a/@title")[0].encode('utf-8')
content_url = each.xpath("./td/a/@href")[0]
content_date = each.xpath("./td[3]/text()")[0]
save = {"title": content_title,
"url": content_url,
"date": content_date, ### 在這裡不要格式化日期,因為save資料在傳輸的時候會被序列化,到下個函式再用的時候,會變成字串
"categories": categories
}
self.crawl(content_url, callback=self.parse_body, save=save)
def parse_body(self, response):
page = response.etree
body_list = page.xpath("//td[@class='bt_content']//text()")
body = ''
for each in body_list:
body += each.strip().encode('utf-8')
result = {"title": response.save["title"],
"categories": response.save["categories"],
"date": self.format_date(response.save["date"]),
"url": response.save["url"],
"body": body,
"update_time": datetime.datetime.now(),
"source": "杭州市人民政府"
}
yield result
def on_result(self, result):
if result is None:
return
# print result
update_key = {
'date': result['date'],
'title': result['title']
}
col.update(update_key, {'$set': result}, upsert=True)