python3多线程读取数据库_python3+sqlite3+多线程爬取某网站文章

之前有爬取过某网站内容,抓取该网站发表的文章内容并保存到数据库,最近又想学一些爬虫方面的知识,所以把之前写的内容翻出来写一写笔记。

首先使用谷歌浏览器分析网页源码,因为该网站是并没有涉及什么js、css渲染等动态网页,所以爬取的过程相对简单。

爬取了该网站的标题、作者、发表时间、评论数、第一张大图的url和内容,然后格式化数据并保存到sqlite3

其过程的实现很简单,就是简单的URL抓包提取网页,然后使用了正则表达式来提取数据,然后进行一些错误的判断和改进,并没有使用到太高级的爬虫技巧,还在继续学习之中。

源码如下:# -*-coding:utf-8-*-import urllib.requestimport reimport sqlite3import timeimport randomimport threadingimport urllib.errorimport sysimport socketimport iofrom datetime import datetimeclass Article(object):

def __init__(self):

self.url="http://wallstreetcn.com/"

self.removeP=re.compile('

')#用来提取正文内容

self.removeRight=re.compile('class=".*?"|align=".*?"|>')

self.removeStrong=re.compile("|")

self.removeAddr=re.compile('|')

self.replaceBR=re.compile('
|
|')

        self.removeImg=re.compile('| {1,7}|&.*?;')

self.removeExtraTag=re.compile('<.>|style=".*?"|value=".*?"')

self.removeNoneLine=re.compile('\\n+')    def get_content(self,article):

#使用正则表达式匹配出标题、作者、日期、内容、第一张大图的url、评论数

title = re.findall(r'

(.*?)

',article,re.S)

author=re.search(r'(.*?)target="_blank">(.*?)(.*?)',article,re.S)

post_at=re.findall(r'(.*?)',article,re.S)

time=post_at[0]

year=time[:4]

month=time[5:7]

day=time[8:10]

hour=time[12:]#对有中文时间格式处理,返回值为datetime格式

p_content=re.findall(r'

',article,re.S)#正文内容有多种类型,分别匹配

span_content=re.findall(r'(.*?)',article,re.S)        if p_content==None:

content=span_content        else:

content=p_content

str_data=''.join(content[:-4])

removed_p=re.sub(self.removeP,'\\n',str_data)

removed_strong=re.sub(self.removeStrong,'',removed_p)

removed_addr=re.sub(self.removeAddr,'',removed_strong)

removed_br=re.sub(self.replaceBR,'\\n',removed_addr)

removed_img=re.sub(self.removeImg,'',removed_br)

removed_tag=re.sub(self.removeExtraTag,'',removed_img)

removed_right=re.sub(self.removeRight,'',removed_tag)

content=re.sub(self.removeNoneLine,'\\n',removed_right)

        img_1=re.search(r'

        img_2=re.search(r'

img=img_1.group(2)        elif img_2!=None:

img=img_2.group(1)        else:

img=None

comment_count=re.findall(r'(.*?)',article,re.S)

try:            if img==None and comment_count==None:#有可能文章没有图片和评论,考虑以下几种情况

return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),None,0

elif img!=None and comment_count==None:                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),str(img),0

elif img==None and comment_count!=None:                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),None,int(comment_count[0])            else:                return str(title[0]),str(author.group(2)),datetime.strptime(year+'-'+month+'-'+day+' '+hour,'%Y-%m-%d %H:%M:%S'),''.join(content),str(img),int(comment_count[0])        except Exception as e:            pass

def create_table(self):

conn=sqlite3.connect('article.db')        #如果不存在一个art表,新建一个art表

conn.execute("CREATE TABLE IF NOT EXISTS art(title varchar(80) PRIMARY KEY not null, author varchar(10),post_at TEXT not null,content varchar(255) not null,img varchar(20) ,comment_count integer);")

conn.close()    def save_content(self,title,author,post_at,content,img,comment_count):

#连接并保存到数据库

conn=sqlite3.connect('article.db')

conn.execute("INSERT INTO art (title,author,post_at,content,img,comment_count)values(?,?,?,?,?,?)",(title,author,post_at,content,img,comment_count))

result=conn.execute("SELECT * FROM art")        return list(result)

conn.close()    def spider(self):

cou=1

for i in random.sample(range(19,247271),10000):#随机生成url,数字可以任意

try:                try:

full_url=self.url+'node'+'/'+str(i)#URL格式

page = urllib.request.urlopen(full_url,timeout=5)#设置请求时间限制

pages= page.read().decode('utf-8','ignore')

lst=self.get_content(pages)                    #self.save_content(lst[0],lst[1],lst[2],lst[3],lst[4],lst[5])#不打印出结果

print(self.save_content(lst[0],lst[1],lst[2],lst[3],lst[4],lst[5]))#打印出结果

print('Downloaded Successfully...\\n')

cou+=1

time.sleep(1)                    if cou>300:#控制爬取300篇文章,可以自行调节文章数量,量力而为

sys.exit()                    else:                        continue

except Exception as e:                    pass

except socket.error as e:                pass

def main(self):

#多线程爬取

my_thread = threading.Thread(target = self.spider)

my_thread.start()

my_thread.join()

if __name__ == '__main__':

a=Article()#实例化

a.create_table()

a.main()到此,一个小小的spider就完成了,就可以实现文章的抓取和保存到数据库了,在dos下的显示如下所示。

最后,由于是第一次写爬虫,不足之处肯定还有很多,欢迎来挑刺,洗耳恭听,一直在学习与进步当中,继续,共勉。

作者:HalShaw

链接:https://www.jianshu.com/p/01c43def734d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
读取数据量大的SQLite3数据库并且不会造成内存溢出,并且采用多线程速度提取,可以考虑使用以下技术: 1. 使用Python内置的sqlite3模块连接到SQLite3数据库,使用fetchmany()方法分批次从数据库中提取数据,避免一次性读取过多数据导致内存溢出。 2. 使用Python的multiprocessing模块实现多线程处理,加速数据提取和处理过程。 示例代码: ```python import sqlite3 import multiprocessing as mp # 每次从数据库读取的行数 BATCH_SIZE = 10000 # 数据处理函数 def process_data(data): # 处理数据的代码 pass # 多线程处理函数 def process_batch(conn, query, offset): # 连接到数据库 conn = sqlite3.connect(conn) # 读取数据 cursor = conn.cursor() cursor.execute(query + ' LIMIT ? OFFSET ?', (BATCH_SIZE, offset)) data = cursor.fetchall() # 处理数据 process_data(data) # 关闭数据库连接 cursor.close() conn.close() # 主函数 def main(): # 连接到SQLite3数据库 conn = sqlite3.connect('database.db') # 查询语句 query = 'SELECT * FROM table_name' # 获取数据总行数 cursor = conn.cursor() cursor.execute(query) total_rows = cursor.fetchone()[0] cursor.close() # 创建进程池 pool = mp.Pool() # 分批次处理数据 for offset in range(0, total_rows, BATCH_SIZE): pool.apply_async(process_batch, args=(conn, query, offset)) # 等待所有线程完成 pool.close() pool.join() # 关闭数据库连接 conn.close() if __name__ == '__main__': main() ``` 请注意,这只是一个示例,具体的实现取决于数据量的大小和计算机的性能。如果处理的数据量非常大,您可能需要考虑使用其他技术来优化性能,如使用多台计算机并行处理、使用数据库索引等。同时,还需要注意线程安全和数据一致性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值