#!/usr/bin/python
#-*- coding:utf-8 -*-
#爬取世紀佳緣
#這個網站是真的煩,剛開始的時候用scrapy框架寫,但是因為剛接觸框架,碰到js渲染的頁面之后就沒辦法了,所以就采用一般的爬蟲了
#js渲染過的數據,可能在網頁源碼里面沒有數據,需要js異步請求提取數據,然后展示,所以爬取這類的數據,只需要找到js發送請求的url就行了
#js發送的請求可能是post(比如這個例子)或者是get(比如豆瓣電影劇情的排行榜),所以要看好是什么請求
import sys
import json
#from lxml import etree
import urllib
import urllib2
reload(sys)
sys.setdefaultencoding("utf-8") #設置默認的編碼格式,把Unicode格式轉換成漢字寫到文件里面的時候需要用到,要配合decode("unicode_escape")使用
class shiji():
def __init__(self):
self.page = 1 #初始化頁面的第幾頁
self.filename = open("sj.json","w") #打開文件用於寫入數據
def parse_page(self):
url = "http://search.jiayuan.com/v2/search_v2.php?" #初始url的前半段,加上后半段發送的是post請求
headers = {"User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"}
formdata = {
"sex":"f",
"key":"",
"stc":"1:11,2:20.25,3:160.170,23:1",
"sn":"default",
"sv":"1",
"p":self.page, #每次數據js異步提取數據的時候只有p變化了,p對應於當前頁面是第幾頁
"f":"select",
"listStyle":"bigPhoto",
"pri_uid":"170633820",
"jsversion":"v5"
}
data = urllib.urlencode(formdata)
request = urllib2.Request( url ,data = data , headers = headers)
response = urllib2.urlopen(request)
# print response.info().get('Content-Encoding') #這會打印出服務器返回數據的壓縮方式,如果未有壓縮則返回None
js = response.read() #返回的response.read()是json格式的,但是首和尾多了一段字符串"##jiayse##"和"##jiayse##",所以下面就處理一下
#print type(js) #字符串類型
js = js.replace("##jiayser##","").replace("//","") #字符串里很牛X的一個函數replace()
#print js
content = json.loads(js) #字典類型(這個字典是大字典,key只有isLogin、count、pageTotal、userInfo,其中userInfo是每個人的資料)
self.parse_person(content['userInfo']) #調用parse_person函數處理大字典的ueerInfo(還是字典類型的),即每個人的資料
# print type(content['userInfo'])#字典類型
def parse_person(self,userinfo):
for i in range(len(userinfo)):
form = {"昵稱":userinfo[i]['nickname'],"年齡":userinfo[i]['age'],"內心獨白":userinfo[i]['shortnote']} #把要爬取的數據寫成一個字典
#print form
#print type(form)
#不能把dict和list類型直接寫入文件, 把字典寫入json文件的時候要把字典轉換成json字符串才行(json.dumps(form))
#decode("unicode_escape")表示把unicode格式轉換成漢字,但用一個這竟然還不行!還要加上上面的import sys... , 真麻煩
form = json.dumps(form).decode("unicode_escape")
self.filename.write(form+"\n") #寫入文件
if self.page <10: #這里隨便寫self.page,只要不超過頁面加載的范圍就行
self.page+=1
self.parse_page() #自加一之后在調用parse_page()函數進行換頁,然后接着爬
if __name__ == "__main__":
sj = shiji()
sj.parse_page() #調用parse_page()函數開始爬取
寫這個爬蟲浪費了一天的時間。。。我是真的菜。
錯誤總結:
關於unicode編碼轉漢字的方法以及UnicodeEncodeError: 'ascii' codec can't encode characters in position問題:
https://www.cnblogs.com/technologylife/p/6071787.html
http://blog.sina.com.cn/s/blog_64a3795a01018vyp.html
把dict寫入文件的時候碰見的報的typeError的解決辦法: http://blog.csdn.net/guoweish/article/details/47106263
另外加一篇ubuntu vim撤銷操作的博客 http://blog.sina.com.cn/s/blog_7e9efc570101ays3.html
收獲:這次的收獲還可以,解決了很多沒見過的bug,第一次爬取js渲染的網頁的數據,值得記得的是:(1).js渲染過得網頁怎么找數據來源(f12 network XHR 找是post請求還是get請求),(2)字符串的強大替換函數replace,(3)字典寫入文件怎么處理 (先轉換成json的字符串再寫入),(4)unicode轉漢字怎么處理(import sys + decode("unicode_escape"))