python爬虫实例
爬虫进阶(一)
前言
实在是太辣鸡了,写个爬虫用了大半天,各种错误都有,这还是很小的项目,一个人搞得大项目那是真滴累,队里其他大佬都准备去线下了,弱鸡只能敲敲代码的分,得加油学习了。。。此次针对的是爬取CSDN
的不同用户的用户ID
、粉丝数量
、点赞数
、评论数
和阅读数
,并且和本地数据库交互,将爬到的数据存放在数据库中,emmmm有一个小问题就是没有涉及去重的算法,本来想在数据库中去重,但是爬一个查一遍数据库实在是浪费资源,索性没有去重了,不过大部分情况下还是不会有重复的。
正言
本来想利用BeautifulSoup
类的,但是后来发现一个真香的 etree
,是在python
第三方库的 lxml
中,这是HTML的解析器,关于解析器的优劣列了张图:
之前用的标准库,目前爬虫都是轻量级,也没开什么线程,体验不到有何区别23333。
但是BeautifulSoup
是在没有etree
香,所以这里说明一下etree
lementTree轻量级的 Python 式的 API ,它由一个 C 实现来提供。相对于 DOM 来说,ET 快了很多而且有很多令人愉悦的 API 可以使用。
在这里是通过xpath
来查找路径的
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。 XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。
从上面这句话我们可以看出来, xpath 是用来查找 XML ,而我们的 HTML 可以认为是语法不标准的 XML 文档,恰巧我们可以通过这种方式来解析 HTML 文档。
我们在使用 xpath 之前,需要先安装 xpath 的依赖库,这个库并不是 Python 提供的标准库,安装语句如下:
pip install lxml
xpath的简单语法如下:
如果嫌麻烦的话,在Chrome中右击检查查找到相应的html时右击有copy选项,可以copy出特定的xpath
,十分方便。
例如当我copy得到xpath路径后,通过如下语句:
fans_num = str(etree.HTML(html_csdn).xpath('//*[@id="fan"]/text()')[0])
#html_csdn是get请求得到的text文本,得到了粉丝数(注意返回的是列表)
连接数据库
python提供了第三方库可以连接mysql
pip install pymysql
通过pymysql.connect
开启连接,然后获取操作游标后,写好sql请求
,最后提交在关闭即可,具体的语法大伙可以自己搜搜,挺简单的,连本菜鸟都会用了,因为爬虫只负责一个数据爬取工作,所以只需要一句 insert 语句就够了。
最终代码:
#coding=utf-8
import re
import requests
import pymysql
from bs4 import BeautifulSoup
from lxml import etree
import time
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'
}
def get_data(url):
res = requests.get(url,headers=headers)
html_csdn = res.text
# to crawl csdn data including these:
read_num = str(etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[2]/dl[5]/dt/span/text()')[0])
fans_num = str(etree.HTML(html_csdn).xpath('//*[@id="fan"]/text()')[0])
likes_num = str(etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[2]/dl[3]/dt/span/text()')[0])
author = str(etree.HTML(html_csdn).xpath('//*[@id="uid"]/span/@username')[0]).replace(" ","").replace("\n","")
comment_num = str(etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[2]/dl[4]/dt/span/text()')[0])
return {"userID":author,"read_num":read_num,"fans_num":fans_num,"likes_num":likes_num,"comment_num":comment_num,"url":url}
def connect():
#connect database
conn = pymysql.connect(
host = 'localhost',
port = 3306,
user = 'root',
password = 'root',
database = 'data',
charset = 'utf8mb4'
)
#Get a cursor object that can execute SQL statements
cursor = conn.cursor()
return {"conn":conn,"cursor":cursor}
connection = connect()
conn = connection['conn']
cursor = connection['cursor']
#insert data into database
def sqlinsert():
sql_insert = "insert into CSDN(userID,read_num,fans_num,likes_num,comment_num) values ('{userID}','{read_num}','{fans_num}','{likes_num}','{comment_num}');".format(**data)
cursor.execute(sql_insert)
conn.commit()
# judge if url is valid and not repeated
def continue_crawl(url_list,max_steps=5):
if(len(url_list) > max_steps):
print("already crawl so many~")
return False
elif(url_list[-1] in url_list[:-1]):
print("already crawl it!")
return False
else:
return True
all_url = []
# get next url and put it in list
def get_url(url):
res = requests.get(url,headers=headers)
html = res.text
all_url = re.findall('<.*?href="(https://blog.csdn.net.*?)".*?',html)
return all_url[-4]
# all you need change is here ,change the first url in url_list
url_list = ['https://blog.csdn.net/crisprx/article/details/107048541']
while continue_crawl(url_list,20):
data = get_data(url_list[-1])
sqlinsert()
next_url = get_url(url_list[-1])
url_list.append(next_url)
print(url_list[-1])
time.sleep(2)
cursor.close()
conn.close()
再贴一个最终的效果图
和数据库的图:
同样会git到github的,请大伙没事点个star
~~
本文地址:https://blog.csdn.net/crisprx/article/details/107066251