多线程版爬取故事网

  • 前言:
    为了能以更高效的速度爬取,尝试采用了多线程
    本博客参照代码及PROJECT来源:http://kexue.fm/archives/4385/

  • 源代码:
     1 #! -*- coding:utf-8 -*-
     2 import requests as rq
     3 import re
     4 import time
     5 import datetime
     6 import pymysql
     7 from multiprocessing.dummy import Pool,Queue #dummy子库是多线程库
     8 import html
     9 from urllib.request import urlopen
    10 from bs4 import BeautifulSoup
    11 unescape = html.unescape #用来实现对HTML字符的转移
    12 
    13 tasks = Queue() #链接队列
    14 tasks_pass = set() #已队列过的链接
    15 results = {} #结果变量
    16 count = 0 #爬取页面总数
    17 tasks.put('/index.html') #把主页加入到链接队列
    18 tasks_pass.add('/index.html') #把主页加入到已队列链接
    19 
    20 def main(tasks):
    21     global results,count,tasks_pass #多线程可以很轻松地共享变量
    22     while True:
    23         url = tasks.get() #取出一个链接
    24         url = 'http://wap.xigushi.com'+url
    25         html = urlopen(url)
    26         bsObj = BeautifulSoup(html.read(), "lxml")
    27         if (bsObj.meta.attrs['charset']=='gb2312'):
    28             web = rq.get(url).content.decode('gbk')  # 这里的编码要看实际情形而定
    29         else:
    30             web = rq.get(url).content.decode('utf8')  # 这里的编码要看实际情形而定
    31 
    32         urls = re.findall('href="(/.*?)"', web) #查找所有站内链接
    33         for u in urls:
    34             if (u not in tasks_pass): #把还没有队列过的链接加入队列
    35                 if ((re.search('images', url)) is None):
    36                     tasks.put(u)
    37                     tasks_pass.add(u)
    38                 else:
    39                     print(u, '---------------------------skipping--------------------------------------------')
    40             else:
    41                 pass
    42 
    43         text = bsObj.title.get_text()
    44         print(datetime.datetime.now(), '   ', url, '   ', text)
    45         db = pymysql.connect("localhost", "testuser", "test123", "TESTDB", charset='gbk')
    46         dbc = db.cursor()
    47         sql = "insert ignore into data1(url,title) values(%s,%s);"
    48         data = (url, text)
    49         dbc.execute(sql, data)
    50         dbc.close()
    51         db.commit()
    52         db.close()
    53         count += 1
    54         if count % 100 == 0:
    55             print(u'%s done.'%count)
    56 
    57 pool = Pool(10, main, (tasks,)) #多线程爬取,4是线程数
    58 total = 0
    59 while True: #这部分代码的意思是如果20秒内没有动静,那就结束脚本
    60     time.sleep(60)
    61     if len(tasks_pass) > total:
    62         total = len(tasks_pass)
    63     else:
    64         break
    65 
    66 pool.terminate()
    67 print("terminated normally")

     


  • BUG:
  1. 数据库并发写入:
    解答来源:https://stackoverflow.com/questions/6650940/interfaceerror-0
    通过将游标的创建移入线程,并在线程内关闭,跑出来的结果比之前好一些,但奇怪的是多几行还是会出现并发报错,奇怪,还能错一半的?猜测将连接也放入线程会好些,或者干脆不用commit提交?结果是不用commit都没有写入数据库...我以为开启了自动提交呢...
    已解决,将数据库连接和游标都放在线程内创建
  2. 神奇地跳过一些数据库里面没有的链接:
    原来是过滤问题...水平真是...
    已解决,修改URL过滤方式
  3. 编码问题真是头都大了...
    encoding error : input conversion failed due to input error, bytes 0xB1 0x80 0xB5 0xC4

    为什么改了那么多次还有...显然是gbk转utf8问题,可是我判断了啊,还是有些网页就是比较乱...

  4. 又是编码问题:
    UnicodeEncodeError: 'gbk' codec can't encode character '\u30fb' in position 86: illegal multibyte sequence

     

  5. 网络错误:
    urllib.error.HTTPError: HTTP Error 503: Forwarding failure

     

转载于:https://www.cnblogs.com/vorphan/p/7468727.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值