美文网首页stata Stata连享会-Python量化我爱编程
《 利用 Python36,基于 Scrapy 框架的爬虫思路

《 利用 Python36,基于 Scrapy 框架的爬虫思路

作者: yannis_lau | 来源:发表于2017-11-05 19:27 被阅读150次

    《 利用 Python36,基于 Scrapy 框架的爬虫思路 》

    (一)引言
    利用爬虫抓取网页数据已经是常见技能,八爪鱼等工具也比较方便,但导出数据需要付费。从长远来看,静下心来学习爬虫也未尝不可。不过还是有一定难度,需要有一些编程的基础,坑多,一般人就别整了。我做的第一个爬虫作品,欢迎有需要的朋友参考。

    (二)目标网址(这是一个JS渲染的网页,网页直接无法解析,风格:网址不变下实现表格的翻页 ):
    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,平台:Python36。

    Python36 -> Pycharm -> CMD -> Scrapy -> Selenium -> Phantomjs -> chrome + xpath helper

    -> MySQL ->Navicat Premium -> ODBC配置 -> Stata等应用层

    (四)编程思路:

    1. Scrapy 下新建项目文件和主爬虫文件解析网页;

    2. 通过 Chrome + Xpath helper 插件,对网页进行初步分析,确定需要抓取的变量字段,获取 xpath 地址;

    3. 编写 Items.py,这部分主要是定义要抓取和写入的字段:
      class MyspiderItem(scrapy.Item):

    以下定义要爬虫的字段名

    id = scrapy.Field() # 序号
    name = scrapy.Field() # 简称
    code = scrapy.Field() # 代码
    issuer = scrapy.Field() # 发行人
    date = scrapy.Field() # 日期
    amount = scrapy.Field() # 发行量
    payway = scrapy.Field() # 付息方式
    rate = scrapy.Field() # 利率
    deadline = scrapy.Field() # 期限
    startdate = scrapy.Field() # 起息日
    enddate = scrapy.Field() # 到期日

    以下定义要写入 MySQL 数据库的字段,注意变量名要与 MySQL 数据表中的字段一致。

    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

    1. 编写通道文件: piplines.py,这部分主要完成将数据写入 MySQL 等数据库:
      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)

    1. 在 setting.py 开启通道文件,配置网页请求的头信息等:

    (1)考虑以网站可能存在防爬机制,为避免服务器识别为机器访问,需要伪装成人工浏览器访问,启用头信息:

    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,
    }

    1. 编写主爬虫文件: D:\scrapy\myspider\mysipder\spiders\chinabond.py,需要在其中完成对网页的解析和元素的提取。

    -- 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')) # 计算总页数,数值型;

    for j in range(1,3): # 在页数范围内爬虫!这里测试为 3,全爬应为:range(1,page_n+1)
    page_i = int(driver.find_element_by_xpath('//*[@id="nowpage"]').text) # 获得当前页的页码,数值型;
    print("当前是第:" + str(page_i) + "页,共计:" + str(page_n) + "页")

    for i in range(2, 22): # 爬取当前页面数据,2—22 表示页面数据是从2-22行,不含表头,一般 tr 代表行,td代表列。
    item = MyspiderItem()
    item['id'] = driver.find_element_by_xpath("//[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[1]").text
    item['name'] = driver.find_element_by_xpath("//
    [@id='bodyTable']/tbody/tr[" + str(i) + "]/td[2]").text
    item['code'] = driver.find_element_by_xpath("//[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[3]").text
    item['issuer'] = driver.find_element_by_xpath("//
    [@id='bodyTable']/tbody/tr[" + str(i) + "]/td[4]").text
    item['date'] = driver.find_element_by_xpath("//[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[5]").text
    item["amount"] = driver.find_element_by_xpath("//
    [@id='bodyTable']/tbody/tr[" + str(i) + "]/td[6]").text
    item["payway"] = driver.find_element_by_xpath("//[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[7]").text
    item["rate"] = driver.find_element_by_xpath("//
    [@id='bodyTable']/tbody/tr[" + str(i) + "]/td[9]").text
    item["deadline"] = driver.find_element_by_xpath("//[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[10]").text
    item["startdate"] = driver.find_element_by_xpath("//
    [@id='bodyTable']/tbody/tr[" + str(i) + "]/td[11]").text
    item["enddate"] = driver.find_element_by_xpath("//*[@id='bodyTable']/tbody/tr[" + str(i) + "]/td[12]").text

    yield item # 发送当前页数据

    driver.find_element_by_xpath('//*[@id="xiayiye"]/a/img').click() # 点击下一页;

    def load_ok(driver): # 判断下一页是否已经完成加载
    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) # 注意,在本例中,翻页后网址不变,网页是JS渲染得到的,因此直接不可解析。因此,也是使用 selenium + Phantomjs 的理由。该句如果网址有变化才考虑回传网页请求,本例是直接两重循还得到。但循环时要先等待网页加载完成才可进行,必须要有这个判断函数。

    (五)运行之,大功告成,哈哈!

    1. 爬虫过程图(164页,3270条记录):
    1.jpg
    1. 数据注入到 MySQL 的截图:
    1. Stata 走 ODBC 通道将数据导入结果

    (附录A) 安装 Scrapy:

    python 下载包:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

                 http://blog.csdn.net/HHTNAN/article/details/77931782
    

    pip3 安装 Scray 爬虫框架的方法:

    ------------------------------------

    1.运行CMD,切换到Python目录,安装pip:python -m pip install --upgrade pip --force-reinstall

    说明:安装后的pip3存在于Scripts目录下,可在CMD中切换到 Python\Scripts\下,运行 pip3 -V 查看版本。

    2.在CMD中,进入Scripts目录下,运行pip3来安装 Scrapy 框架:pip3 install scrapy

    说明:可能遇到的错误:

    ?Microsoft Visual C++ 14.0 is required 这一步报错了,缺少VC组件!

    解决方案1:(不推荐)提示:http://landinghub.visualstudio.com/visual-cpp-build-tools,到页面上下载!建议翻墙后安装,否则会报错!

    解决方案2:(推荐):http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted下载twisted对应版本的whl文件Twisted?17.5.0?cp36?cp36m?win_amd64.whl),

    文件名中,cp后面是python版本,amd64代表64位,运行pip3 install C:\python36\Twisted-17.5.0-cp36-cp36m-win_amd64.whl。

    安装完成后,再次运行: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,不报错为OK!

    4.在CMD中添加路径:path C:\Python36;%path%

    path C:\Python36\Scripts;%path%

    5.chrome XPath Helper:Ctrl + Shift + X 激活 XPath Helper 的控制台,然后您可以在 Query 文本框中

    输入相应 XPath 进行调试了,提取的结果将被显示在旁边的 Result 文本框.

    5.使用firefox浏览器,安装Xpath插件:搜索框中输入:WebDriver Element Locator,点击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爬取相对正规的网页使用"urllib2 + BeautifulSoup + 正则表达式"就能搞定的话;
    那么动态生成的信息页面,如Ajax、JavaScript等就需要通过"Phantomjs + CasperJS + Selenium"来实现了。
    
    
    pip3 install selenium
    pip3 install -U selenium
    
    
    Phantomjs: http://phantomjs.org/  官网下载解压到 python36\scripts\ 下。
    
    
    http://blog.csdn.net/five3/article/details/19085303
    
    
    *  注:解决:“ImportError: cannot import name 'webdriver'” 问题的方法是:不要将自己编写的程序起名为:selenium.py,因为环境路径很可能优先搜索到这个文件,导致python36无法找到其中的模块。
    
    
    from selenium import webdriver
    
    
    driver = webdriver.PhantomJS(executable_path='C:\\Python36\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')  # 注意:路径中必须使用双斜杠才能被识别!
    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.环境:进入CMD,添加环境路径:addpath.cmd,内容如下:

        path C:\Python36;%path%
        path C:\Python36\Scripts;%path%
    

    2.建立工程项目(D:\scrapy\myspider,.\myspider,.\spiders):

    scrapy startproject myspider

    3.建立爬虫文件(D:\scrapy\Tencent\Tencent\spiders\chinabond.py):

    scrapy genspider chinabond "chinabond.com.cn"

    4.进入 pycharm 中编辑;

    5.随时在 CMD 中试运行。

    cd D:
    cd D:\scrapy\Tencent\Tencent\spiders
    scrapy crawl chinabond
    

    (附录C)MySQL 数据库配置:

    • mysql-5.7.18-winx64.绿色版 ,解压到:D:\MySQL\,此时 MySQL 的程序工作目录在:D:\MySQL\bin
      同时将:my-default.ini(已设定好配置)copy到 MySQL目录下(D:\MySQL\),改名:D:\ MySQL \ my.ini
      ============================================================================================

    来源:http://blog.csdn.net/mhmyqn/article/details/17043921/

    (1)先配置环境变量,把mysql所在目录的bin目录添加到path环境变量中,具体请百度。

     说明:这一步也可以不要,如果你已经进入了:bin 目录下。
    
    
    <1> 右键单击我的电脑->属性->高级系统设置(高级)->环境变量
           点击系统变量下的新建按钮
           输入变量名:MYSQL_HOME
           输入变量值:D:\mysql
    <2> 选择系统变量中的Path
           点击编辑按钮
           在变量值中添加变量值:%MYSQL_HOME%\bin
           注意是在原有变量值后面加上这个变量,用;隔开,不能删除原来的变量值,
    

    (2)CMD 窗口重新以管理员身份运行;

    (3)CMD中,在 bin 目录下,安装 mysql 服务:mysqld --install

     显示:Service successfully installed. 
    

    (4)启动 mysql 服务:

     <1> 先在:INI中设置正确的路径(假设目录是:D:\MySQL\;D:\MySQL\bin):
    
    
        找到:D:\MySQL\my-default.ini,或者自己建立一个my.ini文件,修改或增加如下内容:
    
        [mysqld]
        basedir=D:\MySQL
        datadir=D:\MySQL\data
    
    说明:网上有的说配置中的目录分隔符必须是正斜杠‘/’
          但是经过实验,‘/’、‘\’、‘\\’都没有问题,都是可以的。
    
    
      <2> 到 bin 目录下启动服务:net start mysql,如果报错,可考虑先停止、删除原服务,再安装并启动。
          
          mysqld --remove,如果原服务还在:net stop mysql
    
    
          mysqld --install
    
    
          可能需要初始化一下 data 文件夹(可能需要将原行的删掉):mysqld --initialize-insecure --user=mysql
    
    
          net start mysql
    
    
       显示:MySQL 服务正在启动 .  
             MySQL 服务已经启动成功。
    

    (5)连接 mysql 服务:mysql -uroot,进入 MySQL 命令行:mysql>

    (6)退出:exit

    (7) CMD 下设置 mysql 新密码:mysqladmin -u root password 123

    (8)验证一下用密码登录:mysql -uroot -p

    (9)进入 mysql 后,连接到数据库(现在已是 mysql 命令行):

    mysql>

      use mysql
      update user set password=password(123) where user=root;  注意,分号结尾。
      flush privileges 
    

    (附录D)将 MySQL 服务连接到 ODBC 数据通道:


    * 以下:将 MySQL 配置到 win10 的 ODBC(64位数据源),以方便各软件走 ODBC 通道访问。


    • (一)首先请开启 MySQL 服务(具体资料见附录A).

    *(二)为 MySQL 数据库安装并配置 ODBC 驱动

    • (必须安装MySQL的ODBC驱动,不能用 Win10 自带的 SQL server)。
      1. Win10 中:控制面板/管理工具/ODBC(64位数据源),打开后添加:
    •          MySQL ODBC 5.3 Unicode driver 即可。
      
    • 填入信息:选 TCP/IP server, 端口号:3306

    •          Data soure name:mysql(随便填);用户名:root;密码:123
      
    •          Database 选MySQL项(必选), 服务器:localhost 或  127.0.0.1; 
      
    •          可以点 Test 按钮测试一下, 完事点OK就连上了MySQL服务器.
      
    • (三) 例:在 Stata 可操作如下命令:

    • 1.查看 MySQL 中的数据库

    odbc list // 注:之后的操作均可以通过鼠标进行;

    • 2.查看 mysql 数据库中的所有表:

    odbc query "mysql", dialog(complete)

      1. 查看 chinabond 表中的字段名:

    odbc desc "chinabond"

      1. 导入 chinabond 数据表的数据到 stata 内存:
    • odbc load [extvarlist] [if] [in] , {table("TableName")|exec("SqlStmt")}

    •       [load_options connect_options]
      
    • 如果导入错误,可以换种方式:通过菜单导入,勾选 “Do not quote SQL table name ”

    • 等价于加上参数选项:noquote ,因此该参数对于成功导入是很重要的!

    odbc load, table("chinabond") clear noquote user(root) password(123) dsn("mysql")

    2.jpg 2.jpg 3.jpg

    相关文章

      网友评论

        本文标题:《 利用 Python36,基于 Scrapy 框架的爬虫思路

        本文链接:https://www.haomeiwen.com/subject/uuehmxtx.html