2017.12.23
发现房天下论坛版面改版了,之前用的beautifulsoup写的,发现改动很大,这也说明了BS4基于树结构的查询方式的不便之处,页面结构一旦修改,就很难做到代码重用,于是将抓取论坛的函数中beautifulsoup全部换掉了,换成了正则。
(注释部分是beautifulsoup的方式,其中还有navigable类型转换问题没有解决,不可直接运行;未注释的部分是正则表达式的方式,可直接运行。)
def get_luntan(url,headers): lt_name = [] lt_url = [] article_count = [] res = requests.get(url,headers = headers) ''' soup = BeautifulSoup(res.text,'lxml',from_encoding='utf-8') lt_list_left = soup.select('body .articleAre2 .box48L .box13Menu2')[0] lt_list_right = soup.select('body .articleAre2 .box48R .box13Menu2')[0] #lt_lists = (lt_list_left,lt_list_right) #逐个爬取论坛 #for lt_list in lt_lists: for lt in lt_list_left: tags = lt.select('.box48MenuR .box48ListRL a') lt_name.append(str(tags[0].string)) lt_url.append(tags[0]['href']) article_count.append(str(lt.select('.box48MenuR .box48ListRR3 .s1')[2].string)) for lt in lt_list_right: tags = lt.select('.box48MenuR .box48ListRL a') lt_name.append(str(tags[0].string)) lt_url.append(tags[0]['href']) article_count.append(str(lt.select('.box48MenuR .box48ListRR3 .s1')[2].string)) ''' a_list = re.compile('<div class="box48ListRL">(.*?)</div>').findall(res.text) a_range = [i for i in range(0,150) if (i%100<50 and i%100>=0)] for i in a_range: lt_name.append(re.search('target="_blank">(.*?)</a>',a_list[i],re.M|re.I)[1]) lt_url.append(re.search('href=\'(.*?)\'',a_list[i],re.M|re.I)[1]) #将论坛地址存入数据库 for i in range(len(lt_name)): sql = 'insert into luntan(lt_name,lt_url,article_count) values (%s,%s,%s)' sql_params = (lt_name[i],lt_url[i],article_count[i]) saveDB(sql,sql_params) print(len(lt_url))
之前一直用re.compile().findall(),今天发现re.compile.find()是不存在的,如果想只选择一个结果,re.search(pattern, string, flags=0),这样得到的是第一个匹配的结果,flags是一些筛选条件设定:(常用的是re.I | re.M )
正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
另外,在使用search方法的时候,发现,以前使用compile函数的findall()时可以用[0]获取(.*?)中的值,但是search函数用[0]获得的是匹配的全部字符串,而不是(.*?)中的字符串,想要得到(.*?)中的字符串需要用[1],也就是说,我理解的是,compile函数是从0开始得到选定字符串的,而search函数是从1开始得到选定字符串的。
另外,当‘’“”在(.*?)紧邻时,必须转义,否则就会将(.*?)当做字符串而不是匹配符。