实战项目一:爬取QQ群中的人员信息
一、selenium简介
我们模拟登陆用的是selenium库,selenium是一个自动化测试工具,在爬虫中通常用来进行模拟登陆。
(一)实例说明
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
代码功能:1.打开谷歌浏览器,2.自动输入百度网址并打开百度
如果程序执行错误,浏览器没有打开,那么应该是没有装 Chrome 浏览器或者 Chrome 驱动没有配置在环境变量里。下载驱动,然后将驱动文件路径配置在环境变量即可。
(二)元素定位方式
单个元素选取:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
多个元素选取:
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
代码示例:
#获取网页中的h1标签
h1 = driver.find_element_by_name("h1")
#获取网页中所有的h1标签
h1_list = driver.find_elements_by_name("h1")
(三)实现滚动条自动下拉
代码展示:
#将滚动条移动到页面的底部
js="var q=document.documentElement.scrollTop=100000"
driver.execute_script(js)
二、Xpath简介
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。结构关系包括 父、子、兄弟、先辈、后代等。
(一)语法:
表达式 |
功能描述 |
---|---|
nodename |
选取此节点的所有子节点。 |
/ |
从根节点选取。 |
// |
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. |
选取当前节点。 |
… |
选取当前节点的父节点。 |
@ |
选取属性。 |
通配符 |
描述 |
---|---|
* |
匹配任何元素节点。 |
@* |
匹配任何属性节点。 |
node() |
匹配任何类型的节点。 |
(二)实例:
路径表达式 |
结果 |
---|---|
bookstore |
选取 bookstore 元素的所有子节点。 |
/bookstore |
选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book |
选取属于 bookstore 的子元素的所有 book 元素。 |
//book |
选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book |
选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang |
选取名为 lang 的所有属性。 |
路径表达式 |
结果 |
---|---|
/bookstore/* |
选取 bookstore 元素的所有子元素。 |
//* |
选取文档中的所有元素。 |
//title[@*] |
选取所有带有属性的 title 元素。 |
更多语法知识参考:Xpath实现信息提取
代码实例:
#获取 class 为 bold 的标签名
result = html.xpath('//*[@class="bold"]')
三、定义一个爬虫类
(一)导入包
import time
from selenium import webdriver
(二)初始化类
class qqGroupSpider():
'''
Q群爬虫类
'''
def __init__(self, driver,qq,passwd,qqgroup):
'''
初始化根据用户信息登录到Q群管理界面
:param driver:
:param qq:
:param passwd:
:param qqgroup:
:param writefile:
'''
url = "https://qun.qq.com/member.html#gid={}".format(qqgroup)
self.driver=driver
driver.delete_all_cookies()
driver.get(url)
time.sleep(1)
driver.switch_to.frame("login_frame") # 进入登录iframe
time.sleep(1)
change = driver.find_element_by_id("switcher_plogin")
change.click()
driver.find_element_by_id('u').clear() # 选择用户名框
driver.find_element_by_id('u').send_keys(qq)
driver.find_element_by_id('p').clear()
driver.find_element_by_id('p').send_keys(passwd)
driver.find_element_by_class_name("login_button").click()
time.sleep(1)
(三)滚动条自动下拉
def scroll_foot(self,driver):
'''
控制屏幕向下滚动到底部
:param driver:
:return:
'''
js = "var q=document.documentElement.scrollTop=100000"
return driver.execute_script(js)
(四)获取Tbody标签的列表
def getTbodyList(self, driver):
print("getTbodyList()函数运行过")
return driver.find_elements_by_xpath('//div[@class="group-memeber"]//tbody[contains(@class,"list")]')
(五)解析Tbody标签
def parseTbody(self, html):
'''
解析tbody里面的内容,一个tbody里面有多个成员,
解析完成后,返回成员基本情况的列表
:param html:
:return:
'''
# selector = etree.HTML(html)
print("parseTbody()函数运行过")
memberLists = []
for each in html:
memberList = each.find_elements_by_xpath('tr[contains(@class,"mb mb")]')
memberLists += memberList
print("memberLists长度为:{}".format(len(memberLists)))
memberLists_data = []
for each in memberLists:
memberLists_data.append(self.parseMember(each))
return memberLists_data
(六)提取Tbody标签中每个群员的信息
def parseMember(self, mb):
'''
解析每个人各项描述,以逗号隔开,返回一个成员的基本情况
:param mb:
:return:
'''
print("parseMember()函数运行过")
td = mb.find_elements_by_xpath('td')
print("td长度为:{}".format(len(td)))
qId = td[1].text.strip()
nickName = td[2].find_element_by_xpath('span').text.strip()
card = td[3].find_element_by_xpath('span').text.strip()
qq = td[4].text.strip()
sex = td[5].text.strip()
qqAge = td[6].text.strip()
joinTime = td[7].text.strip()
lastTime = td[8].text.strip()
a = (qId + "|" + qq + "|" + nickName + "|" + card + "|" + sex + "|" + qqAge + "|" + joinTime + "|" + lastTime)
print(a)
return a
(七)将提取到群员的信息写入文件
def parseAndWrite(self, tbody):
'''
解析HTML中的tbody,解析完成后写入到本地文件
:param tbody:
:return:
'''
print("parseAndWrite()函数运行过")
memberList = self.parseTbody(tbody)
with open("1607.csv", 'a+', encoding="utf-8") as f:
for each in memberList:
f.write(str(each)+"n")
四、主函数
def main():
qq = "你的QQ账号"
passwd = "你的QQ密码"
qqgroup = "想要爬取的QQ群群号"
driver = webdriver.Chrome()
spider=qqGroupSpider(driver,qq,passwd,qqgroup)
time.sleep(10)
# 找到QQ群的人数
qqNum = int(driver.find_element_by_xpath('//*[@id="groupMemberNum"]').text.strip())
print("QQ群人数为:"+str(qqNum))
curren_qq_num=0
prelen=0
while curren_qq_num != qqNum:
curren_qq_num=len(driver.find_elements_by_xpath('//*[@id="groupMember"]//td[contains(@class,"td-no")]'))
#不停的向下滚动屏幕,直到底部
spider.scroll_foot(driver)
#每次滚动休息1秒
time.sleep(1)
tlist = spider.getTbodyList(driver)
spider.parseAndWrite(tlist[prelen:])
prelen = len(tlist)#更新tbody列表的长度
driver.quit()
if __name__ == '__main__':
main()
- 浙江创新“互联网+心理”服务模式!关爱焦虑抑郁的你
- 大佬 Python 对阵新秀 Julia,谁能问鼎机器学习和数据科学?
- 海外服务器访问变慢如何解决?在线等,急…
- 19条运营线路,北京地铁如何进行智能化运维?
- 未来二十年,产业变革的核心是什么?
- 大数据助你购买航空延误险,飞机延误未必是坏事!
- 作为一个有追求的程序员,你应该掌握的七种武器
- 腾讯云直播答题方案解析
- C+虚函数实现多态性的思考
- Zzreal的大数据笔记-SparkDay04
- 180数字集团品牌升级 启用域名180.ai
- iDC预测全球物联网花费在2018年至7720亿美金
- 北京青年报:用数据说话应是网络强国标配
- 3字母域名谁不爱?游戏门户启用价值六位数的域名
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 批量执行crontab指定条目的注释和解注释
- Rancher集群部署后需要做的几件事
- Ingress(Nginx)日志持久化与可视化(多图预警)
- .Net在Windows上使用Jenkins做CI/CD的那些事
- 【STM32H7】第9章 RL-TCPnet调试方法(Event Recorder和串口两种)
- 【STM32F429】第9章 RL-TCPnet调试方法(Event Recorder和串口两种)
- 【STM32F407】第9章 RL-TCPnet V7.X调试方法(Event Recorder和串口两种)
- CentOS7的udev的绑定规则
- 案例:记录一则强制开库遭遇ORA-16433的处理过程
- mybatis升级为mybatis-plus踩到的坑
- Treepath
- linux 远程ssh免密登录
- npm 安装 electron taobao镜像 404错误 自用 实践笔记
- Asp.net Core 使用Jenkins + Dockor 实现持续集成、自动化部署(二):部署
- 队列的一种实现:循环队列