批处理的简单网络爬虫

@echo off
::# History:
::#   Date        Author      Description
::#   -------------------------------------------------------------
::#   2/10/2014  Perry       Initial created.
::#
::# Note:
::# This source code can be used, modified, and redistributed under the
::# terms of the license agreement that is included in the Spiders package
::# By continuing to use, modify, or redistributed this code you indicate
::# that you have read the license and understand and accept it fully.
::#setlocal enabledelayedexpansion

:begin
::#             Architecture
::#
::#    ┌───────初始化
::#    │                │
::#    │                │
::#    │     ┌队列空─ ◇
::#    │     │         │
::#    │    查表        │
::#    │     │         │     ┌─下载
::#    │     └────启动──┤
::#    │                │     └─下载
::#    │                │     ┌─分析
::#    │               启动──┤
::#    │                │     └─分析
::#    │               统计
::#    │                │
::#    ├──无数据───◇
::#    │                │
::#    └───────存数据
::#

  set $sfldb=database.db
  set $sdofl=sedTMP.txt
  
  set $dwlfd=download
  
  set $prfx1=$a$b$c
  set $tmpx2=$xTmp
  set $tmpx3=$uTmp

::# 最多允许同时运行的下载进程数量。
  set $tsknm=2

::# 每个下载进程最大处理的数据量。
  set $tskmx=5

::# 最多提供给下载进程使用的资源数量。
  set $datmx=5

  set $tblwp=T_Webpages
  set $tblma=T_Mails
  set $tbltm=T_Temp1

  if "%~1"=="CMB" goto :startCMB
  if "%~1"=="DWL" goto :startDWL
  if "%~1"=="AYS" goto :startAYS
  if "%~1"=="TSK" goto :startTSK
  if not "%~1"=="" goto :end
  if exist "%$sfldb%" goto :dbReady

::# 创建一个数据表用来储存模板文件。
  ( gecho create table %$tblwp% \50
    gecho wp_id integer primary key autoincrement not null,
    gecho wp_url text not null unique,
    gecho wp_text text,
    gecho wp_status integer default 0,
    gecho wp_result integer default 0,
    gecho wp_error integer default 0,
    gecho wp_parent integer default 0,
    gecho wp_access datetime,
    gecho wp_update datetime\51;
    gecho create table %$tbltm% \50
    gecho wp_id integer primary key autoincrement not null,
    gecho wp_url text not null unique,
    gecho wp_text text,
    gecho wp_status integer default 0,
    gecho wp_result integer default 0,
    gecho wp_error integer default 0,
    gecho wp_parent integer default 0,
    gecho wp_access datetime,
    gecho wp_update datetime\51;
  ) | sqlite3 "%$sfldb%"

:dbReady
::# 查看当前数据库中是否有内容
  set sql=select count(*) from %$tblwp%;
  for /f %%i in ('sqlite3 "%$sfldb%" "%sql%" 2^>nul') do (
    if %%i gtr 0 goto :cleanStatus)

::# 初始化数据库内容。从网上找了些导航网站。
  set Xed=insert into %$tblwp%^(wp_url,wp_status,wp_parent^) values('http://
  ( gecho begin;
    ( gecho www.0460.com
      gecho www.114la.com
      gecho www.1616.net
      gecho www.2345.com
      gecho www.265.com
      gecho www.5566.net
      gecho www.726.com
      gecho www.baimin.com
      gecho www.hao123.com
      gecho www.hao360.cn
      gecho www.lvse.com
      gecho www.tao123.com
      gecho www.ttuu.com
    ) | gawk "{print ENVIRON[\"Xed\"]$1\"',0,0\x29;\"}"
    gecho commit;
  ) | sqlite3 "%$sfldb%"

:cleanStatus
::# 清除上次未完成项目的状态。
  sqlite3 "%$sfldb%" "update %$tblwp% set wp_status=0 where wp_status=2;"
  for /f "delims==" %%i in ('set $ZX_ 2^>nul') do (
    set %%~i=)

:prepareData
  set x=0
::# 上次剩余的数据。
  for /f %%i in ('set $ZX_ 2^>nul') do set /a x+=1
::# 得到最少数据需求量。
  set /a z=$tsknm*$tskmx*2
::# 如果没有数据不足继续增加数据。
  if %x% geq %z% goto :allocTasks
::# 清除临时变量。
  for /f "delims==" %%i in ('set $ZT_ 2^>nul') do (
    set %%~i=)
::# 从数据库中取出一组未被分析过的网址。
::# 如果数据库在此时被锁定(导入数据时)产生错误导致未能更新会自动重试。
:fetchData
  set z=0
  set sql=select wp_id, wp_url from %$tblwp% where wp_status=0 limit %$datmx%;
  for /f "tokens=1,2 delims=^|" %%i in ('sqlite3 "%$sfldb%" "%sql%" 2^>nul') do (
    set $ZT_%%~i=%%~j
::# 对已经取得的项目计数。
    set /a z+=1)
  set sql=update %$tblwp% set wp_status
::# 判断是否取到数据。
  if %z% equ 0 goto :fetchError
::# 给取出的数据做个标记。
  ( gecho begin;
    set $ZT_ | sed -r -e "s/.+_([0-9]+)=.+/%sql%=2 where wp_id=\1;/"
    gecho commit;) | sqlite3 "%$sfldb%" && goto :appendData
:fetchError
  set z=0
::# 更新出错了,重置已经变更的标记。
  ( gecho begin;
    set $ZT_ | sed -r -e "s/.+_([0-9]+)=.+/%sql%=0 where wp_id=\1;/"
    gecho commit;) | sqlite3 "%$sfldb%"
::# 清除产生的变量。
  for /f "tokens=1,* delims==" %%i in ('set $ZT_ 2^>nul') do (
    set %%~i=)
:appendData
::# 新增的数据项。
  for /f "tokens=2,* delims==_" %%i in ('set $ZT_ 2^>nul') do (
    set $ZX_%%~i=%%~j
    set $ZT_%%~i=)
  goto :prepareData
::# 分配数据给下载进程。
:allocTasks
::# 检查数据是否足够。
  if %x% lss %$tsknm% goto :prepareData
  call "%~0" TSK,%$tsknm%
:statistics
::# 统计有多少进程在下载。
  set z=0
  set c=0
  for /f "tokens=2 delims==_" %%i in ('set $ZC_') do (
    if exist "%%~i_*.dat1" (
      set $ZA_%%~i=%%~i
      set /a c+=1)
    set /a z+=1)
  set /a z-=c
  if %z% lss 5 goto :allocTasks
::#  if %c% gtr 5 start /min call "%~0",AYS
  forfiles /M *.dat1 /C "cmd.exe /c %~1 CMB @fname"
  >nul timeout /t 1
  goto :statistics

::# 存数据。
:importData
  set v1=insert into %$tbltm%(wp_url,wp_status,wp_parent) values('
  set v2=update %$tbltm% set wp_status=1, wp_result=
  set v3=wp_url,wp_text,wp_status,wp_result,wp_error,wp_parent
  set $file=

:findData
::# 找出一个可用的数据文件。
  for %%i in (*.dat2) do (
    set $file=%%~i
    goto :beginImp)
::# 没有文件可用。
  goto :statistics

:beginImp
::# 确保文件有效。
  if not exist "%$file%" (
    goto :findData)

::# 开始导入数据。
  ( gecho begin;
    gecho delete from %$tbltm%;
    gecho delete from sqlite_sequence where name='%$tbltm%';
    cat "%$file%" | gawk "{if(!a[$1]++) print ENVIRON[\"v1\"]$1\"',0,\"$2\"\x29;\"}"
    cat "%$file%" | gawk "{if(!a[$2]++) print ENVIRON[\"v2\"]$3\",wp_error=\"$4\" where wp_id=\"$2\";\"}"
    gecho insert into %$tblwp% \50%v3%\51 select %v3% from %$tbltm% where wp_url not in \50select wp_url from %$tblwp%\51;
    gecho commit;
  ) | sqlite3 "%$sfldb%" || (
    echo 访问数据库出错,准备重试。
    goto :importData)
  erase /f /q "%$file%"
::# 继续找下一个文件直接找不到为止。
  goto :findData

:startTSK
  set c=%~2
:nextTask
  set id=
  set url=
  for /f "tokens=2,* delims==_" %%i in ('set $ZX_ 2^>nul') do (
    set id=%%~i
    set url=%%~j
    goto :getOne)
  goto :end
:getOne
  start /min call "%~0",DWL,"%id%","%url%"
  set $ZC_%id%=%url%
  set $ZX_%id%=
  set /a x-=1
  set /a c-=1
  if %c% gtr 0 goto :nextTask
  goto :end

:startDWL
::# 下载网页内容并保存到文件。
  if "%~3"=="" goto :failDWL
  if "%~2"=="" goto :finishDWL
  if exist "%~2.dat1" goto :finishDWL
  wget --no-check-certificate -c -t2 -T5 -q -O "%~2.dwl" "%~3"
::# if errorlevel 1 goto :failDWL
  if not exist "%~2.dwl" goto :failDWL
::# 找出绝对地址。
  grep -o -E "https?://[a-z0-9A-Z]+[a-z0-9A-Z\-_\.]+" "%~2.dwl" | sort | uniq -i >"%~2.ays"

::# 计算本次下载的网页中共找出了多少网址。
  for /f %%i in ('wc -l "%~2.ays" 2^>nul') do (
    set $count=%%i)

  rename "%~2.ays" "%~2_%$count%.dat1"
  goto :finishDWL
:failDWL
::# 创建一个空文件代表下载完成。
  echo.>"%~2_0.dat1"
:finishDWL
  if exist "%~2.dwl" erase /f "%~2.dwl"
  exit

:startAYS
::# 将数据变成SQL插入语句。
  cat "%$sdofl%" | sed -e "s/$/ %$id% %$count% %$error%/">>"%$output%"

::# 清除掉变量。
  set %$var%=

::# 一次分析出来的数据少于1000条就暂不存数据库。继续分析。
  for /f %%i in ('wc -l "%$output%" 2^>nul') do (
    if %%i lss 1000 goto :next)

::# 将分析出来的数据丢给SQLite3异步处理。
  start /min call "%~0" IMP

::# 不需要等SQLite3处理完,继续去分析下一个URL。
  if %$id% neq 0 goto :startAnalysis
  goto :end

:startCMB
  for /f "tokens=1,2 delims=_." %%i in (%~2) do (
    set id=%%i
    set count=%%j
  ::# 做个标记表示此URL被分析过。
    set $ZA_%%i=
    set $ZC_%%i=
      echo %%i | gawk "{a=$0;for(i=0;i<50-length(a);i++) $0=$0\"\x20\";print \"Analyzed \"$0\"%%j found.\"}"
    erase /f %%i_%%j.%%k
  )

::# 做个标记表示此URL被分析过。
  echo %$first% | gawk "{a=$0;for(i=0;i<50-length(a);i++) $0=$0\"\x20\";print \"Analyzed \"$0\"Found %$count%\"}"

:end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值