《 利用 Python36赞赖,基于 Scrapy 框架的爬蟲思路 》
(一)引言
利用爬蟲抓取網(wǎng)頁數(shù)據(jù)已經(jīng)是常見技能,八爪魚等工具也比較方便通砍,但導(dǎo)出數(shù)據(jù)需要付費(fèi)玛臂。從長遠(yuǎn)來看烤蜕,靜下心來學(xué)習(xí)爬蟲也未嘗不可。不過還是有一定難度迹冤,需要有一些編程的基礎(chǔ)讽营,坑多,一般人就別整了泡徙。我做的第一個(gè)爬蟲作品橱鹏,歡迎有需要的朋友參考。
(二)目標(biāo)網(wǎng)址(這是一個(gè)JS渲染的網(wǎng)頁堪藐,網(wǎng)頁直接無法解析莉兰,風(fēng)格:網(wǎng)址不變下實(shí)現(xiàn)表格的翻頁 ):
http://www.chinabond.com.cn/jsp/include/EJB/queryResult.jsp?pageNumber=1&queryType=0&sType=2&zqdm=&zqjc=&zqxz=07&eYear2=0000&bigPageNumber=1&bigPageLines=500&zqdmOrder=1&fxrqOrder=1&hkrOrder=1&qxrOrder=1&dqrOrder=1&ssltrOrder=1&zqqxOrder=1&fxfsOrder=1&xOrder=12345678&qxStart=0&qxEnd=0&sWhere=&wsYear=&weYear=&eWhere=&sEnd=0&fxksr=-00-00&fxjsr=-00-00&fxStart=-00-00&fxEnd=-00-00&dfStart=-00-00&dfEnd=-00-00&start=0&zqfxr=&fuxfs=&faxfs=00&zqxs=00&bzbh=&sYear=&sMonth=00&sDay=00&eYear=&eMonth=00&eDay=00&fxStartYear=&fxStartMonth=00&fxStartDay=00&fxEndYear=&fxEndMonth=00&fxEndDay=00&dfStartYear=&dfStartMonth=00&dfStartDay=00&dfEndYear=&dfEndMonth=00&dfEndDay=00&col=28%2C2%2C5%2C33%2C7%2C21%2C11%2C12%2C23%2C25
(三)工具:Scrapy + Selenium + Phantomjs,平臺(tái):Python36礁竞。
Python36 -> Pycharm -> CMD -> Scrapy -> Selenium -> Phantomjs -> chrome + xpath helper
-> MySQL ->Navicat Premium -> ODBC配置 -> Stata等應(yīng)用層
(四)編程思路:
Scrapy 下新建項(xiàng)目文件和主爬蟲文件解析網(wǎng)頁糖荒;
通過 Chrome + Xpath helper 插件,對(duì)網(wǎng)頁進(jìn)行初步分析模捂,確定需要抓取的變量字段捶朵,獲取 xpath 地址;
編寫 Items.py狂男,這部分主要是定義要抓取和寫入的字段:
class MyspiderItem(scrapy.Item):
以下定義要爬蟲的字段名
id = scrapy.Field() # 序號(hào)
name = scrapy.Field() # 簡稱
code = scrapy.Field() # 代碼
issuer = scrapy.Field() # 發(fā)行人
date = scrapy.Field() # 日期
amount = scrapy.Field() # 發(fā)行量
payway = scrapy.Field() # 付息方式
rate = scrapy.Field() # 利率
deadline = scrapy.Field() # 期限
startdate = scrapy.Field() # 起息日
enddate = scrapy.Field() # 到期日
以下定義要寫入 MySQL 數(shù)據(jù)庫的字段综看,注意變量名要與 MySQL 數(shù)據(jù)表中的字段一致。
def get_insert_sql(self):
insert_sql="""
insert into chinabond(
id,
name,
code,
issuer,
date,
amount,
payway,
rate,
deadline,
startdate,
enddate
)VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
"""
params=(
self["id"],
self["name"],
self["code"],
self["issuer"],
self["date"],
self["amount"],
self["payway"],
self["rate"],
self["deadline"],
self["startdate"],
self["enddate"],
)
return insert_sql,params
- 編寫通道文件: piplines.py并淋,這部分主要完成將數(shù)據(jù)寫入 MySQL 等數(shù)據(jù)庫:
from twisted.enterprise import adbapi
import pymysql
import pymysql.cursors
class MyspiderPipeline(object):
def init(self,dbpool):
self.dbpool = dbpool
@classmethod
def from_settings(cls,settings):
dbpool = adbapi.ConnectionPool(
"pymysql",
host="localhost",
db="mysql",
user="root",
password="123",
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
use_unicode = True
)
return cls(dbpool)
def process_item(self,item,spider):
self.dbpool.runInteraction(self.do_insert,item)
def do_insert(self,cursor,item):
insert_sql,params=item.get_insert_sql()
cursor.execute(insert_sql,params)
- 在 setting.py 開啟通道文件,配置網(wǎng)頁請(qǐng)求的頭信息等:
(1)考慮以網(wǎng)站可能存在防爬機(jī)制珍昨,為避免服務(wù)器識(shí)別為機(jī)器訪問县耽,需要偽裝成人工瀏覽器訪問,啟用頭信息:
DEFAULT_REQUEST_HEADERS = {
'host': 'www.chinabond.com.cn',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8',
'accept-language': 'zh-CN,zh;q=0.9',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
}
(2)啟用 piplines.py 通道文件:
Configure item pipelines
See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'myspider.pipelines.MyspiderPipeline': 300,
}
- 編寫主爬蟲文件: D:\scrapy\myspider\mysipder\spiders\chinabond.py镣典,需要在其中完成對(duì)網(wǎng)頁的解析和元素的提取兔毙。
-- coding: utf-8 --
import scrapy
from myspider.items import MyspiderItem
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
class ChinabondSpider(scrapy.Spider):
name = 'chinabond'
allowed_domains = ['chinabond.com.cn']
start_urls = ["http://www.chinabond.com.cn/jsp/include/EJB/queryResult.jsp?pageNumber=1&queryType=0&sType=2&zqdm=&zqjc=&zqxz=07&eYear2=0000&bigPageNumber=1&bigPageLines=500&zqdmOrder=1&fxrqOrder=1&hkrOrder=1&qxrOrder=1&dqrOrder=1&ssltrOrder=1&zqqxOrder=1&fxfsOrder=1&xOrder=12345678&qxStart=0&qxEnd=0&sWhere=&wsYear=&weYear=&eWhere=&sEnd=0&fxksr=-00-00&fxjsr=-00-00&fxStart=-00-00&fxEnd=-00-00&dfStart=-00-00&dfEnd=-00-00&start=0&zqfxr=&fuxfs=&faxfs=00&zqxs=00&bzbh=&sYear=&sMonth=00&sDay=00&eYear=&eMonth=00&eDay=00&fxStartYear=&fxStartMonth=00&fxStartDay=00&fxEndYear=&fxEndMonth=00&fxEndDay=00&dfStartYear=&dfStartMonth=00&dfStartDay=00&dfEndYear=&dfEndMonth=00&dfEndDay=00&col=28%2C2%2C5%2C33%2C7%2C21%2C11%2C12%2C23%2C25"]
def parse(self, response):
driver = webdriver.PhantomJS(executable_path='C:\Python36\phantomjs-2.1.1-windows\bin\phantomjs.exe')
url = "http://www.chinabond.com.cn/jsp/include/EJB/queryResult.jsp?pageNumber=1&queryType=0&sType=2&zqdm=&zqjc=&zqxz=07&eYear2=0000&bigPageNumber=1&bigPageLines=500&zqdmOrder=1&fxrqOrder=1&hkrOrder=1&qxrOrder=1&dqrOrder=1&ssltrOrder=1&zqqxOrder=1&fxfsOrder=1&xOrder=12345678&qxStart=0&qxEnd=0&sWhere=&wsYear=&weYear=&eWhere=&sEnd=0&fxksr=-00-00&fxjsr=-00-00&fxStart=-00-00&fxEnd=-00-00&dfStart=-00-00&dfEnd=-00-00&start=0&zqfxr=&fuxfs=&faxfs=00&zqxs=00&bzbh=&sYear=&sMonth=00&sDay=00&eYear=&eMonth=00&eDay=00&fxStartYear=&fxStartMonth=00&fxStartDay=00&fxEndYear=&fxEndMonth=00&fxEndDay=00&dfStartYear=&dfStartMonth=00&dfStartDay=00&dfEndYear=&dfEndMonth=00&dfEndDay=00&col=28%2C2%2C5%2C33%2C7%2C21%2C11%2C12%2C23%2C25"
driver.get(url)
page_n = len(driver.find_elements_by_xpath('//*[@id="sel"]/option')) # 計(jì)算總頁數(shù),數(shù)值型兄春;
for j in range(1,3): # 在頁數(shù)范圍內(nèi)爬蟲澎剥!這里測試為 3,全爬應(yīng)為:range(1,page_n+1)
page_i = int(driver.find_element_by_xpath('//*[@id="nowpage"]').text) # 獲得當(dāng)前頁的頁碼赶舆,數(shù)值型哑姚;
print("當(dāng)前是第:" + str(page_i) + "頁,共計(jì):" + str(page_n) + "頁")
for i in range(2, 22): # 爬取當(dāng)前頁面數(shù)據(jù)芜茵,2—22 表示頁面數(shù)據(jù)是從2-22行叙量,不含表頭,一般 tr 代表行九串,td代表列绞佩。
item = MyspiderItem()
item['id'] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[1]").text
item['name'] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[2]").text
item['code'] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[3]").text
item['issuer'] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[4]").text
item['date'] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[5]").text
item["amount"] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[6]").text
item["payway"] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[7]").text
item["rate"] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[9]").text
item["deadline"] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[10]").text
item["startdate"] = driver.find_element_by_xpath("http://[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[11]").text
item["enddate"] = driver.find_element_by_xpath("http://*[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[12]").text
yield item # 發(fā)送當(dāng)前頁數(shù)據(jù)
driver.find_element_by_xpath('//*[@id="xiayiye"]/a/img').click() # 點(diǎn)擊下一頁;
def load_ok(driver): # 判斷下一頁是否已經(jīng)完成加載
if int(driver.find_element_by_xpath('//*[@id="nowpage"]').text) != page_i:
return 1
else:
return 0
WebDriverWait(driver,20).until(load_ok) # 等待加載完成寺鸥。
yield scrapy.Request(url, callback=self.parse) # 注意,在本例中品山,翻頁后網(wǎng)址不變胆建,網(wǎng)頁是JS渲染得到的,因此直接不可解析肘交。因此笆载,也是使用 selenium + Phantomjs 的理由。該句如果網(wǎng)址有變化才考慮回傳網(wǎng)頁請(qǐng)求酸些,本例是直接兩重循還得到宰译。但循環(huán)時(shí)要先等待網(wǎng)頁加載完成才可進(jìn)行,必須要有這個(gè)判斷函數(shù)魄懂。
(五)運(yùn)行之沿侈,大功告成,哈哈市栗!
- 爬蟲過程圖(164頁缀拭,3270條記錄):
- 數(shù)據(jù)注入到 MySQL 的截圖:
- Stata 走 ODBC 通道將數(shù)據(jù)導(dǎo)入結(jié)果
(附錄A) 安裝 Scrapy:
python 下載包:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
http://blog.csdn.net/HHTNAN/article/details/77931782
pip3 安裝 Scray 爬蟲框架的方法:
------------------------------------
1.運(yùn)行CMD,切換到Python目錄填帽,安裝pip:python -m pip install --upgrade pip --force-reinstall
說明:安裝后的pip3存在于Scripts目錄下蛛淋,可在CMD中切換到 Python\Scripts\下,運(yùn)行 pip3 -V 查看版本篡腌。
2.在CMD中褐荷,進(jìn)入Scripts目錄下,運(yùn)行pip3來安裝 Scrapy 框架:pip3 install scrapy
說明:可能遇到的錯(cuò)誤:
?Microsoft Visual C++ 14.0 is required 這一步報(bào)錯(cuò)了嘹悼,缺少VC組件叛甫!
解決方案1:(不推薦)提示:http://landinghub.visualstudio.com/visual-cpp-build-tools,到頁面上下載杨伙!建議翻墻后安裝其监,否則會(huì)報(bào)錯(cuò)!
解決方案2:(推薦):http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted下載twisted對(duì)應(yīng)版本的whl文件Twisted?17.5.0?cp36?cp36m?win_amd64.whl)限匣,
文件名中抖苦,cp后面是python版本,amd64代表64位米死,運(yùn)行pip3 install C:\python36\Twisted-17.5.0-cp36-cp36m-win_amd64.whl锌历。
安裝完成后,再次運(yùn)行:pip3 install Scrapy1
3.安裝 Win32Py,地址:百度https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/pywin32-221.win-amd64-py3.6.exe/download?use_mirror=jaist
檢查是否成功:import win32com峦筒,不報(bào)錯(cuò)為OK辩涝!
4.在CMD中添加路徑:path C:\Python36;%path%
path C:\Python36\Scripts;%path%
5.chrome XPath Helper:Ctrl + Shift + X 激活 XPath Helper 的控制臺(tái),然后您可以在 Query 文本框中
輸入相應(yīng) XPath 進(jìn)行調(diào)試了勘天,提取的結(jié)果將被顯示在旁邊的 Result 文本框.
5.使用firefox瀏覽器怔揩,安裝Xpath插件:搜索框中輸入:WebDriver Element Locator捉邢,點(diǎn)擊Add to firefox
6.在python中安裝MySQLdb,在CMD中切換到 Python\Scripts\下:pip3 install mysql-python (不支持Python3.6)
6.在python中安裝pymysql商膊,在CMD中切換到 Python\Scripts\下:pip3 install pymysql(可支持Python3.6)
6.下載 pymssql, pip3 install C:\python36\pymssql-2.1.3-cp36-cp36m-win_amd64.whl
在Windows下安裝PIP+Phantomjs+Selenium
如果說在使用Python爬取相對(duì)正規(guī)的網(wǎng)頁使用"urllib2 + BeautifulSoup + 正則表達(dá)式"就能搞定的話伏伐;
那么動(dòng)態(tài)生成的信息頁面,如Ajax晕拆、JavaScript等就需要通過"Phantomjs + CasperJS + Selenium"來實(shí)現(xiàn)了藐翎。
pip3 install selenium
pip3 install -U selenium
Phantomjs: http://phantomjs.org/ 官網(wǎng)下載解壓到 python36\scripts\ 下。
http://blog.csdn.net/five3/article/details/19085303
* 注:解決:“ImportError: cannot import name 'webdriver'” 問題的方法是:不要將自己編寫的程序起名為:selenium.py实幕,因?yàn)榄h(huán)境路徑很可能優(yōu)先搜索到這個(gè)文件吝镣,導(dǎo)致python36無法找到其中的模塊。
from selenium import webdriver
driver = webdriver.PhantomJS(executable_path='C:\\Python36\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe') # 注意:路徑中必須使用雙斜杠才能被識(shí)別昆庇!
driver.get("http://www.baidu.com")
data = driver.title
print(data)
* 添加路徑的方法:import os,sys
sys.path.append("C:\\Python36\\phantomjs-2.1.1-windows\\bin")
* 添加路徑的方法:import os,sys
sys.path.append("C:\\Python36\\phantomjs-2.1.1-windows\\bin")
(附錄B)Scrapy 框架的使用:
1.環(huán)境:進(jìn)入CMD末贾,添加環(huán)境路徑:addpath.cmd,內(nèi)容如下:
path C:\Python36;%path%
path C:\Python36\Scripts;%path%
2.建立工程項(xiàng)目(D:\scrapy\myspider,.\myspider,.\spiders):
scrapy startproject myspider
3.建立爬蟲文件(D:\scrapy\Tencent\Tencent\spiders\chinabond.py):
scrapy genspider chinabond "chinabond.com.cn"
4.進(jìn)入 pycharm 中編輯整吆;
5.隨時(shí)在 CMD 中試運(yùn)行拱撵。
cd D:
cd D:\scrapy\Tencent\Tencent\spiders
scrapy crawl chinabond
(附錄C)MySQL 數(shù)據(jù)庫配置:
- mysql-5.7.18-winx64.綠色版 ,解壓到:D:\MySQL\表蝙,此時(shí) MySQL 的程序工作目錄在:D:\MySQL\bin
同時(shí)將:my-default.ini(已設(shè)定好配置)copy到 MySQL目錄下(D:\MySQL\)拴测,改名:D:\ MySQL \ my.ini
============================================================================================
來源:http://blog.csdn.net/mhmyqn/article/details/17043921/
(1)先配置環(huán)境變量,把mysql所在目錄的bin目錄添加到path環(huán)境變量中府蛇,具體請(qǐng)百度集索。
說明:這一步也可以不要,如果你已經(jīng)進(jìn)入了:bin 目錄下汇跨。
<1> 右鍵單擊我的電腦->屬性->高級(jí)系統(tǒng)設(shè)置(高級(jí))->環(huán)境變量
點(diǎn)擊系統(tǒng)變量下的新建按鈕
輸入變量名:MYSQL_HOME
輸入變量值:D:\mysql
<2> 選擇系統(tǒng)變量中的Path
點(diǎn)擊編輯按鈕
在變量值中添加變量值:%MYSQL_HOME%\bin
注意是在原有變量值后面加上這個(gè)變量务荆,用;隔開,不能刪除原來的變量值扰法,
(2)CMD 窗口重新以管理員身份運(yùn)行蛹含;
(3)CMD中毅厚,在 bin 目錄下塞颁,安裝 mysql 服務(wù):mysqld --install
顯示:Service successfully installed.
(4)啟動(dòng) mysql 服務(wù):
<1> 先在:INI中設(shè)置正確的路徑(假設(shè)目錄是:D:\MySQL\;D:\MySQL\bin):
找到:D:\MySQL\my-default.ini吸耿,或者自己建立一個(gè)my.ini文件祠锣,修改或增加如下內(nèi)容:
[mysqld]
basedir=D:\MySQL
datadir=D:\MySQL\data
說明:網(wǎng)上有的說配置中的目錄分隔符必須是正斜杠‘/’
但是經(jīng)過實(shí)驗(yàn),‘/’咽安、‘\’伴网、‘\\’都沒有問題,都是可以的妆棒。
<2> 到 bin 目錄下啟動(dòng)服務(wù):net start mysql澡腾,如果報(bào)錯(cuò)沸伏,可考慮先停止、刪除原服務(wù)动分,再安裝并啟動(dòng)毅糟。
mysqld --remove,如果原服務(wù)還在:net stop mysql
mysqld --install
可能需要初始化一下 data 文件夾(可能需要將原行的刪掉):mysqld --initialize-insecure --user=mysql
net start mysql
顯示:MySQL 服務(wù)正在啟動(dòng) .
MySQL 服務(wù)已經(jīng)啟動(dòng)成功澜公。
(5)連接 mysql 服務(wù):mysql -uroot姆另,進(jìn)入 MySQL 命令行:mysql>
(6)退出:exit
(7) CMD 下設(shè)置 mysql 新密碼:mysqladmin -u root password 123
(8)驗(yàn)證一下用密碼登錄:mysql -uroot -p
(9)進(jìn)入 mysql 后,連接到數(shù)據(jù)庫(現(xiàn)在已是 mysql 命令行):
mysql>
use mysql
update user set password=password(123) where user=root; 注意坟乾,分號(hào)結(jié)尾迹辐。
flush privileges
(附錄D)將 MySQL 服務(wù)連接到 ODBC 數(shù)據(jù)通道:
* 以下:將 MySQL 配置到 win10 的 ODBC(64位數(shù)據(jù)源),以方便各軟件走 ODBC 通道訪問甚侣。
- (一)首先請(qǐng)開啟 MySQL 服務(wù)(具體資料見附錄A).
*(二)為 MySQL 數(shù)據(jù)庫安裝并配置 ODBC 驅(qū)動(dòng)
- (必須安裝MySQL的ODBC驅(qū)動(dòng)明吩,不能用 Win10 自帶的 SQL server)。
- 下載地址:https://dev.mysql.com/downloads/connector/odbc/,安裝64位驅(qū)動(dòng)渺绒。
- Win10 中:控制面板/管理工具/ODBC(64位數(shù)據(jù)源)贺喝,打開后添加:
MySQL ODBC 5.3 Unicode driver 即可。
填入信息:選 TCP/IP server宗兼, 端口號(hào):3306
Data soure name:mysql(隨便填)躏鱼;用戶名:root;密碼:123
Database 選MySQL項(xiàng)(必選), 服務(wù)器:localhost 或 127.0.0.1;
可以點(diǎn) Test 按鈕測試一下, 完事點(diǎn)OK就連上了MySQL服務(wù)器.
(三) 例:在 Stata 可操作如下命令:
- 1.查看 MySQL 中的數(shù)據(jù)庫
odbc list // 注:之后的操作均可以通過鼠標(biāo)進(jìn)行殷绍;
- 2.查看 mysql 數(shù)據(jù)庫中的所有表:
odbc query "mysql", dialog(complete)
- 查看 chinabond 表中的字段名:
odbc desc "chinabond"
- 導(dǎo)入 chinabond 數(shù)據(jù)表的數(shù)據(jù)到 stata 內(nèi)存:
odbc load [extvarlist] [if] [in] , {table("TableName")|exec("SqlStmt")}
[load_options connect_options]
如果導(dǎo)入錯(cuò)誤染苛,可以換種方式:通過菜單導(dǎo)入,勾選 “Do not quote SQL table name ”
- 等價(jià)于加上參數(shù)選項(xiàng):noquote 主到,因此該參數(shù)對(duì)于成功導(dǎo)入是很重要的茶行!
odbc load, table("chinabond") clear noquote user(root) password(123) dsn("mysql")