学习爬虫有一段时间了,今天想在此写一篇基于新手对爬虫入门的理解和初级爬虫的构建的文章。说白了,这篇文章,是写给比我还菜的人看的。别看了,说的就是你。
一个简单的爬虫构建我们采取一个简单的思路:
抓取网页
本次我们要抓取的页面是全唐诗,它的首页长这样:
依次点进去查看前几个页面的url,我们就会发现这些页面之间的规律:
好了,经过简单的观察,我们发现这些页面的url有一个字段是从0001增长到了0900,一共九百页,而其他地方则没有变化,这就好办了!但是也不要认为这个爬虫就这么简单,这些页面要抓取就是一整页,如何把这一整页诗词抽离出每首诗并写入数据库呢?接下来开始写爬虫
def gethtml(self,url):
try :
response = requests.get(url, headers=self.headers)
response.encoding = 'gb18030'
except :
pass
else :
html = lxml.html.fromstring(response.text)
finally:
return html
这个方法是专门用来抓取网页源代码的,它接受一个网页URL作为参数,将网页源码转换为html元素并返回,并且随时准备被再次调用,至于response的编码,这里采取了gb18030,因为古诗词里面的生僻字太多了,另外再说一句,爬虫新手最头疼的问题编码可能算一个,采用requests库的时候,我们一般调用网页自身的编码方式来给网页的响应流编码:
response.encoding = response.apparent_encoding
但本教程是个例外,因为古诗词里面的生僻字实在是太多了~~~
抽取元素
抽取元素我们使用xpath,高效又简洁,正则表达式和beautifulsoup我都尝试过,但始终不如xpath深入我心。
检查网页源代码,我们只要获取DIV标签下面的文本就好了
page = html.xpath('.//div/text()')
数据处理
上面我说过,这一页诗拿下来我们需要对其做数据抽取,这个时候不着急写代码,应该停下来认真观察拿到的诗文,选择一个最好的规则应用到其中,做到最优化的从诗文集合里分离单首诗文。这里我们注意到,每首诗的标题以「」包围的,我们的规则是上一个包含「」的行到下一个包含「」的行之间的内容为一首诗,然后再把「」里的诗名跟后面的作者都抽离出来,最终写入数据库,代码如下:
import csv
import pymysql
conn = pymysql.connect(host='localhost',port=3306,user='root',password='xxxx',db='xxx',charset='utf8')
cur = conn.cursor()
with open('tangshi.txt','r+',encoding='utf8') as f:
with open('tangshi.csv','w+',encoding='utf8') as csvfile:
writer = csv.writer(csvfile)
items = f.readlines()
lst = []
for index, item in enumerate(items):
if '」' in item:
lst.append(index) #存放了所有标题的索引
for index, item in enumerate(lst): #以索引-值 的形式遍历列表
lst2 = items[item].split('「')
author = lst2[-1].split('」')[-1]
title = lst2[-1].split('」')[-2]
if items[lst[index]] != items[lst[-1]]: #如果这个标题不是最后一个
context = items[lst[index]+1:lst[index+1]]
context = ''.join([i.strip() for i in content if i ]) #做列表转字符串的处理
else:
context = items[lst[index]+1:] #否则诗文是该标题到此文本的末尾
context = ''.join([i.strip() for i in context if i])
sql = 'insert into tangshi(title,author,context) values(%s,%s,%s)'
cur.execute(sql, (title.strip(),author.strip(),context.strip()))
conn.commit()
cur.close()
conn.close()
说到最后,我把爬虫的源代码贴在这里,python环境3.5,应该可以直接运行。时间仓促加上语言不够精炼,可能有些地方说的不够明白,请大家见谅,也欢迎读者提出疑问或者献上你宝贵的意见。下回见!
import requests
import lxml.html
class myspider():
#定义内置方法,跟随类一起创建,全局变量一般在此方法下声明
def __init__(self):
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'
self.headers = {'User-Agent':user_agent}
#定义获取相应url的html
def gethtml(self,url):
try :
response = requests.get(url, headers=self.headers)
response.encoding = 'gb18030'
except :
pass
else :
html = lxml.html.fromstring(response.text)
finally:
return html
def getpage(self,url,num):
with open('D:/{0}.txt'.format(num[1]),'w',encoding='utf8') as f :
for i in range(1,num[0]):
print('正写入第{0}页'.format(i))
s = str(i).zfill(4)
print(s)
ur = url.format(s)
html = self.gethtml(ur)
print(ur)
page = html.xpath('.//div/text()')
for j in page :
if j :
j.strip('\n')
f.write(j)
print('写入完毕')
if __name__=='__main__':
sp = myspider()
url1 = 'http://www.shigeku.org/shiku/gs/tangshi/qts_{0}.htm'
d ={url1:[901,'tangshi']}
for url,num in d.items():
sp.getpage(url,num)